终于会最大流了,简直尿
我终于会最大流啦!以前(若干年前)认真背过ISAP+GAP优化+当前弧优化的超碉模板,不过一次都没用过!
这次我找到了当年的模板,还是pascal的…我怒写了一份C++的。
然后过了一道最大流裸奔题Drainage Ditches(http://poj.org/problem?id=1273)。
然后我又找了一道水题
这题要分点,把一个点分成入点和出点,两个点之间连一条这个点的消耗的边。然后之后它给的边(x,y)就把x的出点和y的入点连起来。这题的河居然可以两个方向流,(y,x)也要连一发……然后改一下出发点和结束点就行了,哐哐哐就是过。
以前学的时候,看网上说ISAP+GAP+当前弧是最碉的最大流算法,怒虐dinic,有没有很碉。
代码:
ISAP+GAP+当前弧:
1 //ISAP+当前弧+GAP,邻接矩阵,起点为1终点为n,先输入m再输入n 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 7 const int MAXN=222;//点数 8 const int inf=0x7fffffff;//MAXINT 9 10 int c[MAXN][MAXN],h[MAXN],g[MAXN],d[MAXN];//c为残留容量邻接矩阵 11 //g[i]为标号为i的结点个数,h[i]为i结点的标号 12 //d[]当前弧优化,记录当前弧 13 bool found; 14 int n,m,st,ed,augc,flow;//n个点m条边,augc为增广路容量,flow为最大流 15 16 void aug(const int m) 17 { 18 int i,augco=augc,mini,minh=n-1; 19 if (m==ed)//如果当前结点为汇点 20 { 21 found=true; 22 flow+=augc; //增加流量 23 return; 24 } 25 for (i=d[m]; i<=n; i++)//寻找容许边 26 if (c[m][i]>0 && h[i]+1==h[m])//如果残留容量大于0,如果是容许边 27 { 28 if (c[m][i]<augc) augc=c[m][i];//如果容许边流量小于当前增广路流量 则更新增广路流量 29 d[m]=i; //把i定为当前弧 30 aug(i); //递归 31 if (h[1]>=n) return; //GAP 如果源点距离标号大于n 则停止算法 32 if (found) break; //如果找到汇点 则退出寻找 33 augc=augco;//没找到就还原当前的流 34 } 35 if (!found) //重标号 36 { 37 for (i=1; i<=n; i++) //找那个标号,这里不能用d[m]开始,不然会蛋疼 38 if (c[m][i]>0 && h[i]<minh) 39 { 40 minh=h[i]; 41 mini=i; 42 } 43 g[h[m]]--; //GAP 距离为 44 if (g[h[m]]==0) h[1]=n; //GAP 45 h[m]=minh+1; 46 d[m]=mini; 47 g[h[m]]++; //GAP 48 } 49 else 50 {//修改残量 51 c[m][i]-=augc; 52 c[i][m]+=augc; 53 } 54 } 55 56 void farm() 57 { 58 int i,j,x,y,z; 59 memset(c,0,sizeof(c)); 60 for(i=0; i<m; i++) 61 { 62 scanf("%d%d%d",&x,&y,&z); 63 c[x][y]+=z; 64 } 65 st=1;ed=n; 66 memset(h,0,sizeof(h)); 67 memset(g,0,sizeof(g)); 68 g[0]=n; 69 flow=0; 70 for(i=1; i<=n; i++) 71 d[i]=1;//当前弧初始化 72 while(h[1]<n) 73 { 74 augc=inf;//初始化增广路容量为正无穷大 75 found=false; 76 aug(1);//从源点开始找 77 } 78 printf("%d\n",flow); 79 } 80 81 int main() 82 { 83 while(scanf("%d%d",&m,&n)!=EOF) farm(); 84 return 0; 85 }
笨笨的洪水渡劫:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 6 const int MAXN=444; 7 const int MAXM=444; 8 const int inf=0x7fffff; 9 10 int c[MAXN][MAXN];//残留容量邻接矩阵 11 12 int h[MAXN],g[MAXN];//g[i]为标号为i的结点个数 h[i]为i结点的标号 13 int augc,flow;//augc为增广路容量,flow为最大流 14 bool found; 15 int d[MAXN];//当前弧优化,记录当前弧 16 int st,ed; 17 18 int n,m;//n个点m条边 19 20 21 void aug(const int m) 22 { 23 int i,augco=augc,mini,minh=n-1; 24 if (m==ed)//如果当前结点为汇点 25 { 26 found=true; 27 flow+=augc; //增加流量 28 return; 29 } 30 for (i=d[m]; i<=n; i++)//寻找容许边 31 if (c[m][i]>0 && h[i]+1==h[m])//如果残留容量大于0,如果是容许边 32 { 33 if (c[m][i]<augc) augc=c[m][i];//如果容许边流量小于当前增广路流量 则更新增广路流量 34 d[m]=i; //把i定为当前弧 35 aug(i); //递归 36 if (h[1]>=n) return; //GAP 如果源点距离标号大于n 则停止算法 37 if (found) break; //如果找到汇点 则退出寻找 38 augc=augco;//没找到就还原当前的流 39 } 40 if (!found) //重标号 41 { 42 for (i=1; i<=n; i++) //找那个标号,这里不能用d[m]开始,不然会蛋疼 43 if (c[m][i]>0 && h[i]<minh) 44 { 45 minh=h[i]; 46 mini=i; 47 } 48 g[h[m]]--; //GAP 距离为 49 if (g[h[m]]==0) h[1]=n; //GAP 50 h[m]=minh+1; 51 d[m]=mini; 52 g[h[m]]++; //GAP 53 } 54 else 55 { 56 //修改残量 57 c[m][i]-=augc; 58 c[i][m]+=augc; 59 } 60 } 61 62 void farm() 63 { 64 int i,j,x,y,z; 65 memset(c,0,sizeof(c)); 66 scanf("%d%d",&n,&m); 67 for(i=2;i<=n;i++) 68 { 69 scanf("%d",&x); 70 c[i][i+n+1]+=x; 71 } 72 c[1][n+2]+=inf; 73 for(i=0; i<m; i++) 74 { 75 scanf("%d%d",&x,&y); 76 x++;y++; 77 c[x+n+1][y]+=inf; 78 c[y+n+1][x]+=inf; 79 } 80 st=1;ed=n+1; 81 n+=n+1; 82 // for(i=1;i<=n;i++) 83 // { 84 // for(j=1;j<=n;j++) 85 // cout<<c[i][j]<<' '; 86 // cout<<endl; 87 // } 88 memset(h,0,sizeof(h)); 89 memset(g,0,sizeof(g)); 90 g[0]=n; 91 flow=0; 92 for(i=1; i<=n; i++) 93 d[i]=1;//当前弧初始化 94 while(h[1]<n) 95 { 96 augc=inf;//初始化增广路容量为正无穷大 97 found=false; 98 aug(st);//从源点开始找 99 } 100 if(flow>=inf) printf("Max!\n"); 101 else if(flow==0) printf("Min!\n"); 102 else printf("%d\n",flow); 103 } 104 105 int main() 106 { 107 int T; 108 scanf("%d",&T); 109 while(T--) farm(); 110 return 0; 111 }