经典的最大流题POJ1273

 

经典的最大流题POJ1273

分类: 网络流 poj图论   1395人阅读  评论(1)  收藏  举报

目录(?)[+]

百度文库花了5分下的 可怜 不过确实是自己需要的东西 吐舌头
经典的最大流题 POJ1273

——其他练习题 POJ3436 

题意描述:

现在有m个池塘(1m开始编号,1为源点,m为汇点),n条水渠,给出这n条水渠所连接的池塘和所能流过的水量,求水渠中所能流过的水的最大容量.一道基础的最大流题目。http://poj.org/problem?id=1273

参考数据:

输入:

5 4

1 2 40

1 4 20

2 4 20

2 3 30

3 4 10

输出:

50

程序实现:

增广路算法Edmonds_Karp

[cpp]  view plain copy
  1. //poj1273_Ek.cpp  
  2. #include<iostream>  
  3. #include<queue>  
  4. using namespace std;  
  5. const int N=201;  
  6. const int INF=99999999;  
  7. int n,m,sum,s,t;//s,t为始点和终点  
  8. int flow[N][N],cap[N][N],a[N],p[N];  
  9. //分别为:flow[u][v]为<u,v>流量、cap[u][v]为<u,v>容量、a[i]表示源点s到节点i的路径上的最小残留量、p[i]记录i的前驱  
  10. int min(int a,int b)  
  11. {  
  12. return a<=b?a:b;  
  13. }  
  14. void Edmonds_Karp()  
  15. {  
  16. int i,u,v;  
  17. queue<int>q;//队列,用bfs找增广路  
  18. while(1)  
  19. {  
  20.    memset(a,0,sizeof(a));//每找一次,初始化一次  
  21.    a[s]=INF;  
  22.    q.push(s);//源点入队  
  23.    while(!q.empty())  
  24.    {  
  25.     u=q.front();  
  26.     q.pop();  
  27.     for(v=1;v<=m;v++)  
  28.     {  
  29.      if(!a[v]&&flow[u][v]<cap[u][v])  
  30.      {  
  31.       p[v]=u;  
  32.       q.push(v);  
  33.       a[v]=min(a[u],cap[u][v]-flow[u][v]);//s-v路径上的最小残量  
  34.      }  
  35.     }  
  36.    }  
  37.    if(a[m]==0)//找不到增广路,则当前流已经是最大流  
  38.     break;  
  39.    sum+=a[m];//流加上  
  40.    for(i=m;i!=s;i=p[i])// //从汇点顺着这条增广路往回走  
  41.    {  
  42.     flow[p[i]][i]+=a[m];//更新正向流量  
  43.     flow[i][p[i]]-=a[m];//更新反向流量  
  44.    }  
  45. }  
  46. printf("%d\n",sum);  
  47. }  
  48. int main()  
  49. {  
  50. //freopen("in.txt","r",stdin);  
  51. int v,u,w;  
  52.     while(scanf("%d%d",&n,&m)!=EOF)  
  53. {  
  54.    s=1;//从1开始  
  55.    t=m;//m为汇点  
  56.    sum=0;//记录最大流量  
  57.    memset(flow,0,sizeof(flow));//初始化  
  58.    memset(cap,0,sizeof(cap));  
  59.    while(n--)  
  60.    {  
  61.     scanf("%d%d%d",&u,&v,&w);  
  62.     cap[u][v]+=w;//注意图中可能出现相同的边  
  63.    }  
  64.    Edmonds_Karp();  
  65. }  
  66. return 0;  
  67. }  



空间优化: poj1273_Ek_youhua.cpp

在程序实现的时候,我们通常只是用一个cap数组来记录容量,而不记录流量,当流量+1的时候,我们可以通过容量-1来实现,以方便程序的实现。正向用cap[u][v],则反向用cap[v][u]表示。

[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<queue>  
  3. using namespace std;  
  4. const int N=201;  
  5. const int INF=99999999;  
  6. int n,m,sum,s,t,w;//s,t为始点和终点  
  7. int cap[N][N],a[N],p[N];  
  8. int min(int a,int b)  
  9. {  
  10. return a<=b?a:b;  
  11. }  
  12. void Edmonds_Karp()  
  13. {  
  14. int i,u,v;  
  15. queue<int>q;//队列,用bfs找增广路  
  16. while(1)  
  17. {  
  18.    memset(a,0,sizeof(a));//每找一次,初始化一次  
  19.    a[s]=INF;  
  20.    q.push(s);//源点入队  
  21.    while(!q.empty())  
  22.    {  
  23.     u=q.front();  
  24.     q.pop();  
  25.     for(v=1;v<=m;v++)  
  26.     {  
  27.      if(!a[v]&&cap[u][v]>0)  
  28.      {  
  29.       p[v]=u;  
  30.       q.push(v);  
  31.       a[v]=min(a[u],cap[u][v]);//s-v路径上的最小残量  
  32.      }  
  33.     }  
  34.    }  
  35.    if(a[m]==0)//找不到增广路,则当前流已经是最大流  
  36.     break;  
  37.    sum+=a[m];//流加上  
  38.    for(i=m;i!=s;i=p[i])// //从汇点顺着这条增广路往回走  
  39.    {  
  40.     cap[p[i]][i]-=a[m];//更新正向流量  
  41.     cap[i][p[i]]+=a[m];//更新反向流量  
  42.    }  
  43. }  
  44. printf("%d\n",sum);  
  45. }  
  46. int main()  
  47. {  
  48. // freopen("in.txt","r",stdin);  
  49. int v,u;  
  50.     while(scanf("%d%d",&n,&m)!=EOF)  
  51. {  
  52.    s=1;//从1开始  
  53.    t=m;//m为汇点  
  54.    sum=0;//记录最大流量  
  55.    memset(cap,0,sizeof(cap));//初始化  
  56.    while(n--)  
  57.    {  
  58.     scanf("%d%d%d",&u,&v,&w);  
  59.     cap[u][v]+=w;//注意图中可能出现相同的边  
  60.    }  
  61.    Edmonds_Karp();  
  62. }  
  63. return 0;  
  64. }  


Dinic邻接矩阵实现:poj1273_Dinic.cpp


[cpp]  view plain copy
  1. #include <cstdio>   
  2.  #include <cstring>   
  3.  #include <cstdlib>   
  4.  #include <iostream>   
  5.  #define min(x,y) ((x<y)?(x):(y))   
  6.  using namespace std;   
  7.  const int MAX=0x5fffffff;//   
  8.  int tab[250][250];//邻接矩阵    
  9.  int dis[250];//距源点距离,分层图    
  10.  int q[2000],h,r;//BFS队列 ,首,尾    
  11.  int N,M,ANS;//N:点数;M,边数    
  12.  int BFS()   
  13.  { int i,j;   
  14.  memset(dis,0xff,sizeof(dis));//以-1填充    
  15.  dis[1]=0;   
  16.  h=0;r=1;   
  17.  q[1]=1;   
  18.  while (h<r)   
  19.  {   
  20.  j=q[++h];   
  21.  for (i=1;i<=N;i++)   
  22.  if (dis[i]<0 && tab[j][i]>0)   
  23.  {   
  24.  dis[i]=dis[j]+1;    
  25.  q[++r]=i;   
  26.  }   
  27.  }   
  28.  if (dis[N]>0)   
  29.  return 1;   
  30.  else   
  31.  return 0;//汇点的DIS小于零,表明BFS不到汇点    
  32.  }   
  33.  //Find代表一次增广,函数返回本次增广的流量,返回0表示无法增广    
  34.  int find(int x,int low)//Low是源点到现在最窄的(剩余流量最小)的边的剩余流量   
  35.  {   
  36.  int i,a=0;   
  37.  if (x==N)return low;//是汇点    
  38.  for (i=1;i<=N;i++)   
  39.  if (tab[x][i] >0 //联通    
  40.  && dis[i]==dis[x]+1 //是分层图的下一层    
  41.  &&(a=find(i,min(low,tab[x][i]))))//能到汇点(a <> 0)    
  42.  {   
  43.  tab[x][i]-=a;   
  44.  tab[i][x]+=a;   
  45.  return a;   
  46.  }   
  47.  return 0;   
  48.    }   
  49.  int main()   
  50.  {   
  51.  //freopen("ditch.in" ,"r",stdin );   
  52.  //freopen("ditch.out","w",stdout);   
  53.  int i,j,f,t,flow,tans;   
  54.  while (scanf("%d%d",&M,&N)!=EOF){   
  55.  memset(tab,0,sizeof(tab));   
  56.  for (i=1;i<=M;i++)   
  57.  {   
  58.  scanf("%d%d%d",&f,&t,&flow);   
  59.  tab[f][t]+=flow;   
  60.  }   
  61.  //   
  62.  ANS=0;   
  63.  while (BFS())//要不停地建立分层图,如果BFS不到汇点才结束    
  64.  {   
  65.  while(tans=find(1,0x7fffffff))ANS+=tans;//一次BFS要不停地找增广路,直到找不到为止    
  66.  }   
  67.  printf("%d\n",ANS);   
  68.  }   
  69.   //system("pause");   
  70.  }  

Dinic邻接表实现poj1273_dinic.cpp

[cpp]  view plain copy
  1. //#define LOCAL  
  2. #include <stdio.h>  
  3. #include <string.h>  
  4. #include <queue>  
  5. using namespace std;  
  6.   
  7. #define MAXN 210  
  8. #define INF 0x3f3f3f3f  
  9.   
  10. struct Edge  
  11. {  
  12.     int st, ed;  
  13.     int c;  
  14.     int next;  
  15. }edge[MAXN << 1];  
  16.   
  17. int n, m;  
  18. int s, t;  
  19. int ans;  
  20. int e = 0;   
  21. int head[MAXN];  
  22. int d[MAXN];  
  23.   
  24. int min(int a, int b)  
  25. {  
  26.     return a < b ? a : b;  
  27. }  
  28.   
  29. void init()  
  30. {  
  31.     int i, j;  
  32.     int a, b, c;   
  33.     s = 1;  
  34.     t = m;  
  35.     e = 0;  
  36.     ans = 0;  
  37.     memset(head, -1, sizeof(head));  
  38.     for(i = 1; i <= n; i++)  
  39.     {  
  40.         scanf("%d%d%d", &a, &b, &c);  
  41.         edge[e].st = a;  
  42.         edge[e].ed = b;  
  43.         edge[e].c = c;  
  44.         edge[e].next = head[a];  
  45.         head[a]= e++;  
  46.         edge[e].st = b;  
  47.         edge[e].ed = a;  
  48.         edge[e].next = head[b];  
  49.         head[b] = e++;  
  50.     }  
  51. }  
  52.   
  53. int bfs()  
  54. {  
  55.     memset(d, -1, sizeof(d));  
  56.     queue<int> q;  
  57.     d[s] = 0;  
  58.     q.push(s);  
  59.     int i;  
  60.     int cur;  
  61.     while(!q.empty())  
  62.     {  
  63.         cur = q.front();  
  64.         q.pop();  
  65.         for(i = head[cur]; i != -1; i = edge[i].next)  
  66.         {  
  67.             if(d[edge[i].ed] == -1 && edge[i].c > 0)  
  68.             {  
  69.                 d[edge[i].ed] = d[cur] + 1;   
  70.                 q.push(edge[i].ed);  
  71.             }     
  72.         }  
  73.     }  
  74.     if(d[t] < 0)  
  75.         return 0;  
  76.     return 1;  
  77. }  
  78.   
  79. int dinic(int x, int flow)  
  80. {  
  81.     if(x == t)  
  82.         return flow;  
  83.     int i, a;  
  84.     for(i = head[x]; i != -1; i = edge[i].next)  
  85.     {  
  86.         if(d[edge[i].ed] == d[x] + 1 && edge[i].c > 0 && (a = dinic(edge[i].ed, min(flow, edge[i].c))))  
  87.         {  
  88.             edge[i].c -= a;  
  89.             edge[i ^ 1].c += a;  
  90.             return a;     
  91.         }  
  92.     }  
  93.     return 0;  
  94. }  
  95.   
  96. void solve()  
  97. {  
  98.     while(scanf("%d%d", &n, &m) != EOF)  
  99.     {  
  100.         init();  
  101.         while(bfs())  
  102.         {  
  103.             int increment;  
  104.             increment = dinic(1, INF);  
  105.                 ans +=  increment;   
  106.         }  
  107.         printf("%d\n", ans);  
  108.     }  
  109. }  
  110.   
  111. int main()  
  112. {  
  113. #ifdef LOCAL  
  114.     freopen("poj1273.txt""r", stdin);  
  115.     // freopen(".txt", "w", stdout);  
  116. #endif  
  117.     solve();  
  118.     return 0;  
  119. }  


SAP实现:poj1273_SAP.cpp

/* 

编者感悟:

sap学了很长时间,一直不敢下手写,结果就是不写永远不会真正的理解算法的含义,sap理论很多算法书上都有讲解,但我还是建议看数学专业 图论的书,比如 《有向图的理论,算法及应用》,这本书的内容非常棒,相信看过的都知道吧,比其他算法书上讲的透多了。
SAP有个优化就是 当出现断链时,就可以直接退出,还有个优化是当前弧的优化,这两个优化只需要一句话+一个数组就解决了,相当实惠,好的ISAP执行的效率真的非常高,我写的ISAP用的是链式前向星法表示。
这个就算是模板了吧,虽然写的不是很好。。

*/

 

[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<cstdio>  
  3. #include<memory.h>  
  4. #include<cmath>  
  5. using namespace std;  
  6. #define MAXN 500  
  7. #define MAXE 40000  
  8. #define INF 0x7fffffff  
  9. long ne,nv,tmp,s,t,index;  
  10. struct Edge{  
  11.     long next,pair;  
  12.     long v,cap,flow;  
  13. }edge[MAXE];  
  14. long net[MAXN];  
  15. long ISAP()  
  16. {  
  17.     long numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN];  
  18.     long cur_flow,max_flow,u,tmp,neck,i;  
  19.     memset(dist,0,sizeof(dist));  
  20.     memset(numb,0,sizeof(numb));  
  21.     memset(pre,-1,sizeof(pre));  
  22.     for(i = 1 ; i <= nv ; ++i)  
  23.         curedge[i] = net[i];  
  24.     numb[nv] = nv;  
  25.     max_flow = 0;  
  26.     u = s;  
  27.     while(dist[s] < nv)  
  28.     {  
  29.         /* first , check if has augmemt flow */  
  30.         if(u == t)  
  31.         {  
  32.             cur_flow = INF;  
  33.             for(i = s; i != t;i = edge[curedge[i]].v)   
  34.             {    
  35.                 if(cur_flow > edge[curedge[i]].cap)  
  36.                 {  
  37.                     neck = i;  
  38.                     cur_flow = edge[curedge[i]].cap;  
  39.                 }  
  40.             }  
  41.             for(i = s; i != t; i = edge[curedge[i]].v)  
  42.             {  
  43.                 tmp = curedge[i];  
  44.                 edge[tmp].cap -= cur_flow;  
  45.                 edge[tmp].flow += cur_flow;  
  46.                 tmp = edge[tmp].pair;  
  47.                 edge[tmp].cap += cur_flow;  
  48.                 edge[tmp].flow -= cur_flow;  
  49.             }  
  50.             max_flow += cur_flow;  
  51.             u = neck;  
  52.         }  
  53.         /* if .... else ... */  
  54.         for(i = curedge[u]; i != -1; i = edge[i].next)  
  55.             if(edge[i].cap > 0 && dist[u] == dist[edge[i].v]+1)  
  56.                 break;  
  57.         if(i != -1)  
  58.         {  
  59.             curedge[u] = i;  
  60.             pre[edge[i].v] = u;  
  61.             u = edge[i].v;  
  62.         }else{  
  63.             if(0 == --numb[dist[u]]) break;  
  64.             curedge[u] = net[u];  
  65.             for(tmp = nv,i = net[u]; i != -1; i = edge[i].next)  
  66.                 if(edge[i].cap > 0)  
  67.                     tmp = tmp<dist[edge[i].v]?tmp:dist[edge[i].v];  
  68.             dist[u] = tmp + 1;  
  69.             ++numb[dist[u]];  
  70.             if(u != s) u = pre[u];  
  71.         }  
  72.     }  
  73.       
  74.     return max_flow;  
  75. }  
  76. int main() {  
  77.     long i,j,np,nc,m,n;  
  78.     long a,b,val;  
  79.     long g[MAXN][MAXN];  
  80.     while(scanf("%d%d",&ne,&nv)!=EOF)  
  81.     {  
  82.         s = 1;  
  83.         t = nv;  
  84.         memset(g,0,sizeof(g));  
  85.         memset(net,-1,sizeof(net));  
  86.         for(i=0;i<ne;++i)  
  87.         {  
  88.             scanf("%ld%ld%ld",&a,&b,&val);  
  89.             g[a][b] += val;  
  90.          }  
  91.          for(i=1;i<=nv;++i)  
  92.              for(j = i; j <= nv;++j)  
  93.                  if(g[i][j]||g[j][i])  
  94.                  {  
  95.                      edge[index].next = net[i];  
  96.                      edge[index].v = j;  
  97.                      edge[index].cap = g[i][j];  
  98.                      edge[index].flow = 0;  
  99.                      edge[index].pair = index+1;  
  100.                      net[i] = index++;  
  101.                      edge[index].next = net[j];  
  102.                      edge[index].v = i;  
  103.                      edge[index].cap = g[j][i];  
  104.                      edge[index].flow = 0;  
  105.                      edge[index].pair = index-1;  
  106.                      net[j] = index++;  
  107.                  }  
  108.         printf("%ld\n",ISAP());  
  109.     }  
  110.     return 0;  
  111. }  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值