网络流网络流小总结
Posted Konjak谷弱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了网络流网络流小总结相关的知识,希望对你有一定的参考价值。
一、dinic最大流
我的模板。模板上已经有了dfs上的优化(比我以前的快多了。。)优化啊优化。
bool bfs(int st,int ed) { while(!q.empty()) q.pop(); memset(d,-1,sizeof(d)); q.push(st); d[st]=0; while(!q.empty()) { int x=q.front();q.pop(); for(int i=first[x];i!=-1;i=a[i].next) { int y=a[i].y; if(d[y]==-1 && a[i].d>0) { d[y]=d[x]+1; q.push(y); } } } return (d[ed]!=-1); } int dfs(int x,int flow,int ed) { int k,p,r=0; if(x==ed) return flow; for(int i=first[x];i!=-1;i=a[i].next) { int y=a[i].y; if(d[y]==d[x]+1 && a[i].d>0) { p=minn(a[i].d,flow-r); p=dfs(y,p,ed); r+=p; //优化,把从这个点开始能流的全部流了 a[i].d-=p; a[i^1].d+=p; } if(r==flow) break; // 优化 } if(!r) d[x]=-1; //优化 return r; } int dinic(int st,int ed) { int ans=0; while(bfs(st,ed)) { int k; while(k=dfs(st,INF,ed)) ans+=k; } return ans; }
二、上下界网络流
建立超级源点ss,超级汇点tt(上图中的s改为ss,t改为tt)
对于每条x到y,下界为k1,上界为k2的边(x,y,k1,k2),拆成如图这种形式:(x,y,k2-k1)(自由流),(ss,y,k1)(必须流入),(x,tt,k1)(必须流出)。
(1)没有源点和汇点:
可行流:跑一遍最大流,看是否满流。满流则有可行流。
最大流:每条边加一个费用f=1,然后跑最大费用循环流(详见下面)。
最小流:每条边加一个费用f=1,然后跑最小费用循环流。
(2)有源点和汇点:
原来的源点s,原来的汇点t。在s和t之间建边(t,s,INF),使原图变为无源汇的循环流。
可行流:拆边后跑一遍最大流,满流则有可行流。
最大流:去掉ss、tt(去掉后无论怎么跑都是已经满足了下界的可行流),然后从原来的源汇点s到t跑一遍最大流,让残余网络的增广路全部加上去。此时(s,t,INF)的那条边的反向边(t,s)的流量就是答案。
最小路:去掉ss、tt后,从原来的源汇点t到s跑一遍最大流(逆向求解,让最多的流量还回去)。
上下界网络路讲解:http://www.cnblogs.com/kane0526/archive/2013/04/05/3001108.html
模板(poj2396)
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<queue> 6 #include<vector> 7 using namespace std; 8 9 const int N=500,M=500,INF=(int)1e9; 10 const int S=N+M+4; 11 int n,m,s,t,ss,tt,len,sum,bk; 12 int d[N+M+4],p[N][M],first[N+M+4],map[2][N][M]; 13 struct node{int x,y,d,next;}a[N*M*2]; 14 queue<int> q; 15 16 int minn(int x,int y){return x<y ? x:y;} 17 int maxx(int x,int y){return x>y ? x:y;} 18 19 void ins(int x,int y,int d) 20 { 21 a[++len].x=x;a[len].y=y;a[len].d=d; 22 a[len].next=first[x];first[x]=len; 23 if(x==ss) sum+=d; 24 swap(x,y); 25 a[++len].x=x;a[len].y=y;a[len].d=0; 26 a[len].next=first[x];first[x]=len; 27 } 28 29 void make_edge(int x,int y) 30 { 31 if(map[0][x][y]>map[1][x][y]) bk=0; 32 if(map[0][x][y]==0) ins(x,y,map[1][x][y]); 33 else 34 { 35 ins(ss,y,map[0][x][y]); 36 ins(x,tt,map[0][x][y]); 37 ins(x,y,map[1][x][y]-map[0][x][y]); 38 } 39 } 40 41 void build(char c,int x,int y,int z) 42 { 43 int t1=0,t2=INF; 44 if(c==\'=\') t1=t2=z; 45 if(c==\'>\') t1=z+1; 46 if(c==\'<\') t2=z-1; 47 map[0][x][y]=maxx(map[0][x][y],t1); 48 map[1][x][y]=minn(map[1][x][y],t2); 49 50 } 51 52 bool bfs(int st,int ed) 53 { 54 while(!q.empty()) q.pop(); 55 memset(d,-1,sizeof(d)); 56 q.push(st); 57 d[st]=0; 58 while(!q.empty()) 59 { 60 int x=q.front();q.pop(); 61 for(int i=first[x];i!=-1;i=a[i].next) 62 { 63 int y=a[i].y; 64 if(d[y]==-1 && a[i].d>0) 65 { 66 d[y]=d[x]+1; 67 q.push(y); 68 } 69 } 70 } 71 return (d[ed]!=-1); 72 } 73 74 int dfs(int x,int flow,int ed) 75 { 76 int k,p,r=0; 77 if(x==ed) return flow; 78 for(int i=first[x];i!=-1;i=a[i].next) 79 { 80 int y=a[i].y; 81 if(d[y]==d[x]+1 && a[i].d>0) 82 { 83 p=minn(a[i].d,flow-r); 84 p=dfs(y,p,ed); 85 r+=p; 86 a[i].d-=p; 87 a[i^1].d+=p; 88 } 89 } 90 if(!r) d[x]=-1; 91 return r; 92 } 93 94 int dinic(int st,int ed) 95 { 96 int ans=0; 97 while(bfs(st,ed)) 98 { 99 int k; 100 while(k=dfs(st,INF,ed)) ans+=k; 101 } 102 return ans; 103 } 104 105 int main() 106 { 107 freopen("a.in","r",stdin); 108 freopen("a.out","w",stdout); 109 int T; 110 scanf("%d",&T); 111 while(T--) 112 { 113 scanf("%d%d",&n,&m); 114 int x,y,z,k; 115 char c; 116 s=n+m+1;t=s+1;ss=t+1;tt=ss+1; 117 len=-1;sum=0;bk=1; 118 memset(first,-1,sizeof(first)); 119 memset(map[0],0,sizeof(map[0])); 120 memset(map[1],63,sizeof(map[1])); 121 memset(p,0,sizeof(p)); 122 int sum1=0,sum2=0; 123 for(int i=1;i<=n;i++) 124 { 125 scanf("%d",&x); 126 map[0][s][i]=map[1][s][i]=x; 127 make_edge(s,i); 128 sum1+=x; 129 } 130 for(int i=n+1;i<=n+m;i++) 131 { 132 scanf("%d",&x); 133 map[0][i][t]=map[1][i][t]=x; 134 make_edge(i,t); 135 sum2+=x; 136 } 137 if(sum1!=sum2) bk=0; 138 scanf("%d",&k); 139 for(int i=1;i<=k;i++) 140 { 141 scanf("%d%d",&x,&y);getchar(); 142 scanf("%c%d",&c,&z); 143 if(x && y) build(c,x,y+n,z); 144 if(!x && y) 145 for(int j=1;j<=n;j++) 146 build(c,j,y+n,z); 147 if(x && !y) 148 for(int j=1;j<=m;j++) 149 build(c,x,j+n,z); 150 if(!x && !y) 151 for(int j=1;j<=n;j++) 152 for(int l=1;l<=m;l++) 153 build(c,j,l+n,z); 154 } 155 for(int i=1;i<=n;i++) 156 for(int j=n+1;j<=n+m;j++) 157 make_edge(i,j); 158 ins(t,s,INF); 159 if(!bk || dinic(ss,tt)!=sum) printf("IMPOSSIBLE\\n"); 160 else 161 { 162 for(int i=0;i<len;i++) 163 { 164 x=a[i].x;y=a[i].y; 165 if(x<=n+m && y<=n+m) 166 { 167 if(!p[x][y-n]) p[x][y-n]=map[0][x][y]+a[i^1].d; 168 } 169 } 170 for(int i=1;i<=n;i++) 171 { 172 for(int j=1;j<=m;j++) 173 printf("%d ",p[i][j]); 174 printf("\\n"); 175 } 176 } 177 printf("\\n"); 178 } 179 return 0; 180 }
三、最小费用最大流
在满足最大流的前提下求最小费用,就是在bfs的时候找一条费用最小的增广路。
1 void ins(int x,int y,int d,int f) 2 { 3 a[++len].x=x;a[len].y=y;a[len].d=d;a[len].f=f; 4 a[len].next=first[x];first[x]=len; 5 a[++len].x=y;a[len].y=x;a[len].d=0;a[len].f=-f; 6 a[len].next=first[y];first[y]=len; 7 } 8 9 int bfs(int st,int ed) 10 { 11 while(!q.empty()) q.pop(); 12 memset(pre,-1,sizeof(pre)); 13 memset(dis,63,sizeof(dis)); 14 memset(in,0,sizeof(in)); 15 memset(flow,0,sizeof(flow)); 16 pre[st]=0;dis[st]=0;in[st]=1;flow[st]=INF;q.push(st); 17 while(!q.empty()) 18 { 19 int x=q.front();in[x]=0;q.pop(); 20 for(int i=first[x];i!=-1;i=a[i].next) 21 { 22 int y=a[i].y; 23 if(a[i].d && dis[y]>dis[x]+a[i].f) 24 { 25 dis[y]=dis[x]+a[i].f; 26 pre[y]=i; 27 flow[y]=minn(a[i].d,flow[x]); 28 if(!in[y]) {in[y]=1;q.push(y);} 29 } 30 } 31 } 32 if(pre[ed]==-1) return -1; 33 return flow[ed]; 34 } 35 36 void MFMC(int st,int ed)//max flow min cost 37 { 38 int k,p; 39 fl=0,cl=0; 40 while((k=bfs(st,ed))!=-1) 41 { 42 fl+=k; 43 cl+=dis[ed]*k; 44 p=ed; 45 while(p!=st) 46 { 47 a[pre[p]].d-=k; 48 a[pre[p]^1].d+=k; 49 p=a[pre[p]].x; 50 } 51 } 52 }
四、最小割
根据最大流最小割原理,最大流就是最小割。主要是建图模型。
经典例题:一些资源,要不给A,要不给B,有相应的收益,问最大收益。写在我的题表里了。
我写了题解:http://www.cnblogs.com/KonjakJuruo/p/5516479.html
五、最大费用循环流
每条边有上下界k1、k2,费用f。问最大费用循环流。
对于每条边(x,y,k1,k2,f),拆成:
1.(x,y,k1,k1,f) (再按上下界拆边,即(s,y,k1,f) (x,t,k1,f)), (x到y之间一定要流k1的流量)
2.(y,x,k2-k1,-f) , (s,y,k2-k1,0) , (x,t,k2-f1,f); (x到y之间有k2-k1的自由流,先假设全部都可以得到,然后建(y,x,k2-k1,-f)就是给它反悔的机会,如果必须反悔就减回f*流量)
跑最大流,用k2的和判满流,满流则有解。
重点来了,题表及代码:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<queue> 6 #include<vector> 7 using namespace std; 8 9 const int N=500,M=500,INF=(int)1e9; 10 const int S=N+M+4; 11 int n,m,s,t,ss,tt,len,sum,bk; 12 int d[N+M+4],p[N][M],first[N+M+4],map[2][N][M]; 13 struct node{int x,y,d,next;}a[N*M*2]; 14 queue<int> q; 15 16 int minn(int x,int y){return x<y ? x:y;} 17 int maxx(int x,int y){return x>y ? x:y;} 18 19 void ins(int x,int y,int d) 20 { 21 a[++len].x=x;a[len].y=y;a[len].d=d; 22 a[len].next=first[x];first[x]=len; 23 if(x==ss) sum+=d; 24 swap(x,y); 25 a[++len].x=x;a[len].y=y;a[len].d=0; 26 a[len].next=first[x];first[x]=len; 27 } 28 29 void make_edge(int x,int y) 30 { 31 if(map[0][x][y]>map[1][x][y]) bk=0; 32 if(map[0][x][y]==0) ins(x,y,map[1][x][y]); 33 else 34 { 35 ins(ss,y,map[0][x][y]); 36 ins(x,tt,map[0][x][y]); 37 ins(x,y,map[1][x][y]-map[0][x][y]); 38 } 39 } 40 41 void build(char c,int x,int y,int z) 42 { 43 int t1=0,t2=INF; 44 if(c==\'=\') t1=t2=z; 45 if(c==\'>\') t1=z+1; 46 if(c==\'<\') t2=z-1; 47 map[0][x][y]=maxx(map[0][x][y],t1); 48 map[1][x][y]=minn(map[1][x][y],t2); 49 50 } 51 52 bool bfs(int st,int ed) 53 { 54 while(!q.empty()) q.pop(); 55 memset(d,-1,sizeof(d)); 56 q.push(st); 57 d[st]=0; 58 while(!q.empty()) 59 { 60 int x=q.front();q.pop(); 61 for(int i=first[x];i!=-1;i=a[i].next) 62 { 63 int y=a[i].y; 64 if(d[y]==-1 && a[i].d>0) 65 { 66 d[y]=d[x]+1; 67 q.push(y); 68 } 69 } 70 } 71 return (d[ed]!=-1); 72 } 73 74 int dfs(int x,int flow,int ed) 75 { 76 int k,p,r=0; 77 if(x==ed) return flow; 78 for(int i=first[x];i!=-C#流总结(文件流内存流网络流BufferedStreamStreamReader/StreamWriterTextReader/TextWriter)