USACO 4.4.2 追查坏牛奶 oj1341 网络流最小割问题

描述 Description
你第一天接手三鹿牛奶公司就发生了一件倒霉的事情:公司不小心发送了一批有三聚氰胺的牛奶。很不幸,你发现这件事的时候,有三聚氰胺的牛奶已经进入了送货网。这个送货网很大,而且关系复杂。你知道这批牛奶要发给哪个零售商,但是要把这批牛奶送到他手中有许多种途径。送货网由一些仓库和运输卡车组成,每辆卡车都在各自固定的两个仓库之间单向运输牛奶。在追查这些有三聚氰胺的牛奶的时候,有必要保证它不被送到零售商手里,所以必须使某些运输卡车停止运输,但是停止每辆卡车都会有一定的经济损失。你的任务是,在保证坏牛奶不送到零售商的前提下,制定出停止卡车运输的方案,使损失最小。
输入格式 Input Format
第一行: 两个整数N(2<=N<=32)、M(0<=M<=1000), N表示仓库的数目,M表示运输卡车的数量。仓库1代 表发货工厂,仓库N代表有三聚氰胺的牛奶要发往的零售商。 第2..M+1行: 每行3个整数Si,Ei,Ci。其中Si,Ei表示这 辆卡车的出发仓库,目的仓库。Ci(0 <= C i <= 2,000,000) 表示让这辆卡车停止运输的损失。
输出格式 Output Format
第1行两个整数c、t,c表示最小的损失,T表示要停止的最少卡车数。接下来t 行表示你要停止哪几条线路。如果有多种方案使损失最小,输出停止的线路最少的方案。如果仍然还有相同的方案,请选择开始输入顺序最小的。
样例输入 Sample Input

4 5
1 3 100
3 2 50
2 4 60
1 2 40
2 3 80

样例输出 Sample Output

60 1
3

时间限制 Time Limitation
1s
注释 Hint
1s
来源 Source
usaco 4.4.2

不得不说这道题真的是毒,输出最小割,割的边数,以及割的方案。

因为只有1000条边,我们将每条边的流量*1001+1,求出最大流后/1001即是最大流【相信能理解】,%1001之后就是割的边数【这也很好理解】。

  最难的第三个问题:输出割的方案。虽然可以通过:枚举每条边,先去掉这条边,然后再求最大流,如果最大流的减小值是这条边的权值,那么这条边就在内,输出即可。然而虽然数据量支持我们这么做,但是OJ的数据..........1000条1到4的边,流量都是2000000。虽然可以在评测姬变卡之后仍能过去【gy0.7s此点】,但是写的不知道为什么我自己本地0.9s。但是发现树神有更高级的写法:

  从源点进行DFS遍历,如果到下一条边流量不为0,继续遍历标记。最后对于每个点枚举它的边,如果x到y有边,x标记,y为标记,说明这条边在最小割中。然而OJ是有数据卡这个方法的。这个方法求的边是第一个遇到的最小割,然而如果1 2 3 4四个点,之间流量都是10,边如下:3 4 10,2 3 10,1 2 10。因为题目要求给出多种方法,按边的序号字典序输出,这四个点割一条边,肯定是都可以的,正解是输出1【3 4这条边,序号为1】。但是图中按此法显然我们求出的是1 ,2。

  我们便可以发现问题了。但是这种数据只能用来卡序号,这就需要此方法求得的这条边能导致后面不连通。那么显然这条边流量是满的。后面如果出现更优解【字典序更小】,那么也必须流量是满的,且流量一样,并满足边数等于前面。

   但是,这也并不是正解,仍然会被卡掉。正解还是删边求最大流。

  1 #include<bits/stdc++.h>
  2 #define ll long long
  3 #define INF 2100000000
  4 using namespace std;
  5 int level[100];
  6 int q[100];
  7 int lin[100];
  8 int rev[5500];
  9 bool f[100];
 10 bool fe[5500];
 11 int len=0;
 12 ll ans=0;
 13 int cnt[5500];
 14 struct www
 15 {
 16     ll v;
 17     int id;
 18 }a[40][40],b[40][40],c[1011];
 19 ll n,m;
 20 ll s,t;
 21 struct qaq{
 22     int nt,y;
 23     ll v;
 24 }e[5500];
 25
 26 char buf[1<<15],*fs,*ft;
 27 inline char getc(){ return(fs==ft && (ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++; }
 28 ll read()
 29 {
 30     ll x=0;
 31     char ch=getc();
 32     while(!isdigit(ch)) ch=getc();
 33     while(isdigit(ch)) {x=(x<<3)+(x<<1)+ch-‘0‘; ch=getc();}
 34     return x;
 35 }
 36
 37 void insert(int x,int y,ll v)
 38 {
 39     e[++len].nt=lin[x]; e[len].v=v; e[len].y=y; lin[x]=len; rev[len]=len+1; fe[len]=1;
 40     e[++len].nt=lin[y]; e[len].v=0; e[len].y=x; lin[y]=len; rev[len]=len-1;
 41 }
 42
 43 bool make_level()
 44 {
 45     ll head=0,tail=1;
 46     memset(level,-1,sizeof(level));
 47     q[1]=s;level[s]=0;
 48     while(head++<tail)
 49     {
 50         ll x=q[head];
 51         for(ll i=lin[x];i;i=e[i].nt)
 52             if(e[i].v && level[e[i].y]==-1)
 53             {
 54                 level[e[i].y]=level[x]+1;
 55                 q[++tail]=e[i].y;
 56             }
 57     }
 58     return level[t]>=0;
 59 }
 60
 61 ll max_flow(ll k,ll flow)
 62 {
 63     if(k==t) return flow;
 64     ll maxflow=0;
 65     ll v;
 66     for(ll i=lin[k];i && (maxflow<flow);i=e[i].nt)
 67         if(e[i].v && level[e[i].y]==level[k]+1)
 68             if(v=max_flow(e[i].y,min(e[i].v,flow-maxflow)))
 69                 maxflow+=v,e[i].v-=v,e[rev[i]].v+=v;
 70     if(!maxflow) level[k]=-1;
 71     return maxflow;
 72 }
 73
 74 ll dinic()
 75 {
 76     ans=0;
 77     ll v;
 78     while(make_level())
 79         while(v=max_flow(s,INF))
 80             ans+=v;
 81     return ans;
 82 }
 83
 84 void dfs(int k)
 85 {
 86     f[k]=1;
 87     for(int i=lin[k];i;i=e[i].nt)
 88     {
 89         if(!f[e[i].y]&&e[i].v)
 90             dfs(e[i].y);
 91     }
 92 }
 93
 94 int main()
 95 {
 96     freopen("a.txt","r",stdin);
 97     freopen("b.txt","w",stdout);
 98     n=read();
 99     m=read();
100     s=1,t=n;
101     for(ll i=1;i<=m;++i)
102     {
103         int x=read(),y=read();
104         ll v=read();
105         c[i].v=v;
106         insert(x,y,v*1001+1);
107     }
108     ll tmp=dinic();
109     //cout<<tmp<<endl;
110     printf("%lld %lld\n",tmp/1001,tmp%1001);
111     bool flag=0;
112     for(int i=1;i<=m;i++)
113         if(c[i].v==tmp/1001)
114         {
115             cout<<i<<endl;
116             flag=1;
117         }
118     if(flag==1) return 0;
119     dfs(1);
120     //cout<<"--------"<<endl;
121     //for(int i=1;i<=n;i++) cout<<f[i]<<‘ ‘;cout<<endl;
122     int haha=0;
123     for(int i=1;i<=n;i++)
124     {
125         for(int j=lin[i];j;j=e[j].nt)
126         {
127             if(f[i]&&!f[e[j].y]&&fe[j])
128                 cnt[++haha]=(j+1)>>1;
129         }
130     }
131     sort(cnt+1,cnt+1+haha);
132     for(int i=1;i<=haha;i++) cout<<cnt[i]<<endl;
133     return 0;
134 }

时间: 2024-08-27 16:31:06

USACO 4.4.2 追查坏牛奶 oj1341 网络流最小割问题的相关文章

【bzoj3144】[Hnoi2013]切糕 网络流最小割

题目描述 输入 第一行是三个正整数P,Q,R,表示切糕的长P. 宽Q.高R.第二行有一个非负整数D,表示光滑性要求.接下来是R个P行Q列的矩阵,第z个 矩阵的第x行第y列是v(x,y,z) (1≤x≤P, 1≤y≤Q, 1≤z≤R). 100%的数据满足P,Q,R≤40,0≤D≤R,且给出的所有的不和谐值不超过1000. 输出 仅包含一个整数,表示在合法基础上最小的总不和谐值. 样例输入 2 2 2 1 6 1 6 1 2 6 2 6 样例输出 6 题目大意 给定一个p行q列的矩阵,每个位置可以

二分图&amp;网络流&amp;最小割等问题的总结

二分图基础: 最大匹配:匈牙利算法 最小点覆盖=最大匹配 最小边覆盖=总节点数-最大匹配 最大独立集=点数-最大匹配 网络流: 带下界网络流 最小割问题的总结: *意义 1.加inf的边表示不能被割,通常用于体现某个点必须属于某个集合 连边(s,u,w)代表如果u不在s割的话需要付出代价w 2.连边(u,v,w)代表如果u在s割,v在t割需要付出代价w 但注意,如果u在t割,v在s割是不需要付出代价的. 那么如果连边(u,v,w)以及(v,u,w)则说明当u与v所属割不同的时候需要付出代价w *

HDU 2435 There is a war (网络流-最小割)

There is a war Problem Description There is a sea. There are N islands in the sea. There are some directional bridges connecting these islands. There is a country called Country One located in Island 1. There is another country called Country Another

【bzoj3630】[JLOI2014]镜面通道 对偶图+计算几何+网络流最小割

题目描述 在一个二维平面上,有一个镜面通道,由镜面AC,BD组成,AC,BD长度相等,且都平行于x轴,B位于(0,0).通道中有n个外表面为镜面的光学元件,光学元件α为圆形,光学元件β为矩形(这些元件可以与其他元件和通道有交集,具体看下图).光线可以在AB上任一点以任意角度射入通道,光线不会发生削弱.当出现元件与元件,元件和通道刚好接触的情况视为光线无法透过(比如两圆相切).现在给出通道中所有元件的信息(α元件包括圆心坐标和半径xi,yi,ri,β元件包括左下角和右上角坐标x1,y1,x2,y2

【bzoj2127】happiness 网络流最小割

题目描述 高一一班的座位表是个n*m的矩阵,经过一个学期的相处,每个同学和前后左右相邻的同学互相成为了好朋友.这学期要分文理科了,每个同学对于选择文科与理科有着自己的喜悦值,而一对好朋友如果能同时选文科或者理科,那么他们又将收获一些喜悦值.作为计算机竞赛教练的scp大老板,想知道如何分配可以使得全班的喜悦值总和最大. 输入 第一行两个正整数n,m.接下来是六个矩阵第一个矩阵为n行m列 此矩阵的第i行第j列的数字表示座位在第i行第j列的同学选择文科获得的喜悦值.第二个矩阵为n行m列 此矩阵的第i行

【bzoj2132】圈地计划 网络流最小割

题目描述 最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地.据了解,这块土地是一块矩形的区域,可以纵横划分为N×M块小区域.GDOI要求将这些区域分为商业区和工业区来开发.根据不同的地形环境,每块小区域建造商业区和工业区能取得不同的经济价值.更具体点,对于第i行第j列的区域,建造商业区将得到Aij收益,建造工业区将得到Bij收益.另外不同的区域连在一起可以得到额外的收益,即如果区域(I,j)相邻(相邻

ZOJ3792_Romantic Value(网络流/最小割=最大流/找割边)

解题报告 题目传送门 题意: 给出一个无向图,以及起点与终点.要删除一些边使得起点与终点不连通,在删掉边的权值之和最小的情况下要求删除的边数尽量少. 求出一个比值:剩余边数权值和/删除的边数. 思路: 明显的让起点终点达不到就是一个最小割,用最大流可以求出. 但是求割边边数就不会了,没做过最小割的求割边问题. 割边一定是残留网络中零流的边,但零流不一定是割边. 飞神的想法很奇特.链接传送 可以把残留网络的零流的边设成容量为1,其他设成无穷,再求一次最大流.最后流量一定等于割边边数 另外: 还有一

HDU 4289 Control (网络流-最小割)

Control Problem Description You, the head of Department of Security, recently received a top-secret information that a group of terrorists is planning to transport some WMD 1 from one city (the source) to another one (the destination). You know their

POJ3469_Dual Core CPU(网络流/最小割=最大流/模版)----Dinic模版2.0

解题报告 题目传送门 题意: 双核CPU,n个模块,每个模块必须运行在某个CPU核心上,每个模块在cpu单核的消耗A和B,M对模块要共享数据,如果在同一个核心上不用消耗,否则需要耗费.安排N个模块,使得总耗费最小 思路: 将两个cpu核心看成源点和汇点,其他模块分别与源点汇点连线(表示每个模块可以在任意cpu上运行),m对模块分别连双向边,要使得模块只能在一个cpu上运行,就是找到一个割,源点和汇点必不联通,耗费最少就是最小割,最小割最大流原理转换成求最大流. 这题数据大,没优化TLE了,加了两