读书人

HDU 3549 Flow Problem 答题报告(EK)

发布时间: 2012-08-30 09:55:54 作者: rapoo

HDU 3549 Flow Problem 解题报告(EK)算法

转载请注明出处:http://write.blog.csdn.net/postlist


题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3549

这是一题裸的网络流题目。说有1000条边,可是只有十五个点,所以实际的边数最多只有15*15。EK复杂度O(VE2),5秒的时间、太多了!


可是,可是!! 就是这题搞的我很悲伤,几次TLE+WA+RE。。。。前天想到昨天近十二点,终于找到错误!


先贴上第一次错误代码

[cpp] view plaincopy
  1. #include<iostream>
  2. #include<algorithm>
  3. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include<string.h>
  6. #include<queue>
  7. #include<math.h>
  8. #define MAXN 20
  9. #define INF 1000
  10. #define MIN(x,y) (x<y?x:y)
  11. using namespace std;
  12. int map[MAXN][MAXN];
  13. int maxflow(int num,int map[][MAXN],int s,int t)
  14. {
  15. int flow[MAXN][MAXN],max_flow[MAXN],fa[MAXN],myqueue[MAXN];
  16. int i,j,temp,qfront,qend,ans=0;
  17. memset(flow,0,sizeof(flow));
  18. while(1)
  19. {
  20. qfront=qend=0;
  21. myqueue[qend++]=s;
  22. fa[s]=-2;
  23. max_flow[s]=INF;
  24. memset(fa,-1,sizeof(fa));
  25. while(qfront<qend)
  26. {
  27. temp=myqueue[qfront++];
  28. for(i=0;i<num;i++) if(fa[i]==-1 && map[temp][i]>flow[temp][i])
  29. {
  30. fa[i]=temp;
  31. myqueue[qend++]=i;
  32. max_flow[i]=MIN(max_flow[temp],map[temp][i]-flow[temp][i]);
  33. }
  34. if(fa[t]!=-1)
  35. {
  36. int k=t;
  37. while(fa[k]>=0)
  38. {
  39. flow[fa[k]][k]+=max_flow[t];//在这,应该加flow[k][fa[k]]-=max_flow[t];
  40. k=fa[k];
  41. }
  42. break;
  43. }
  44. }
  45. if(fa[t]==-1) return ans;
  46. else ans+=max_flow[t];
  47. }
  48. }
  49. int main()
  50. {
  51. int i,j,n,m,t,a,b,c;
  52. scanf("%d",&t);
  53. for(j=1;j<=t;j++)
  54. {
  55. memset(map,0,sizeof(map));
  56. scanf("%d%d",&n,&m);
  57. for(i=0;i<m;i++)
  58. {
  59. scanf("%d%d%d",&a,&b,&c);
  60. map[a-1][b-1]+=c;
  61. }
  62. int ans=maxflow(n,map,0,n-1);
  63. printf("Case %d: %d\n",j,ans);
  64. }
  65. return 0;
  66. }



然后总结下错误原因:1、TLE:while(1)下面第四行,先赋值fa[s]=-2,再memset(fa,0,sizeof(fa));导致后面找到增广路后记录flow直接死循环(实在不知道为什么,求解)。 2、wa:记录flow时也应该记录相应的反向边!



下面贴上正解:


[cpp] view plaincopy
  1. #include<iostream>
  2. #include<algorithm>
  3. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include<string.h>
  6. #include<queue>
  7. #include<math.h>
  8. #define MAXN 20
  9. #define INF 1000
  10. #define MIN(x,y) (x<y?x:y)
  11. using namespace std;
  12. int map[MAXN][MAXN];
  13. int maxflow(int num,int map[][MAXN],int s,int t)
  14. {
  15. int flow[MAXN][MAXN],max_flow[MAXN],fa[MAXN],myqueue[MAXN];
  16. int i,j,temp,qfront,qend,ans=0;
  17. memset(flow,0,sizeof(flow));
  18. while(1)
  19. {
  20. qfront=qend=0;
  21. myqueue[qend++]=s;
  22. max_flow[s]=INF;
  23. memset(fa,-1,sizeof(fa));
  24. fa[s]=-2;
  25. while(qfront<qend)
  26. {
  27. temp=myqueue[qfront++];
  28. for(i=0;i<num;i++) if(fa[i]==-1 && map[temp][i]>flow[temp][i])
  29. {
  30. fa[i]=temp;
  31. myqueue[qend++]=i;
  32. max_flow[i]=MIN(max_flow[temp],map[temp][i]-flow[temp][i]);
  33. }
  34. }
  35. if(fa[t]!=-1)
  36. {
  37. int k=t;
  38. while(fa[k]!=-2)
  39. {
  40. flow[fa[k]][k]+=max_flow[t];
  41. flow[k][fa[k]]-=max_flow[t];
  42. k=fa[k];
  43. }
  44. }
  45. if(fa[t]==-1) return ans;
  46. else ans+=max_flow[t];
  47. }
  48. }
  49. int main()
  50. {
  51. int i,j,n,m,t,a,b,c;
  52. scanf("%d",&t);
  53. for(j=1;j<=t;j++)
  54. {
  55. memset(map,0,sizeof(map));
  56. scanf("%d%d",&n,&m);
  57. for(i=0;i<m;i++)
  58. {
  59. scanf("%d%d%d",&a,&b,&c);
  60. map[a-1][b-1]+=c;
  61. }
  62. int ans=maxflow(n,map,0,n-1);
  63. printf("Case %d: %d\n",j,ans);
  64. }
  65. return 0;
  66. }

应该在宽搜后面加判断是否找到增广路。由于本题WA太久,第一次的AC我是用queue重新敲的。顺便贴上吧,时间差不多。都是一个算法:


[cpp] view plaincopy
  1. #include<iostream>
  2. #include<algorithm>
  3. #include<stdio.h>
  4. #include<stdlib.h>
  5. #include<string.h>
  6. #include<queue>
  7. #include<math.h>
  8. #define MAXN 20
  9. #define INF 0x7fffffff
  10. #define MIN(x,y) (x<y?x:y)
  11. using namespace std;
  12. int flow[MAXN][MAXN],map[MAXN][MAXN],fa[MAXN],a[MAXN];
  13. int maxflow(int num,int map[][MAXN],int s,int t)
  14. {
  15. int ans=0;
  16. memset(flow,0,sizeof(flow));
  17. while(1)
  18. {
  19. queue<int> q;
  20. q.push(s);
  21. memset(a,0,sizeof(a));
  22. a[s]=INF;
  23. while(!q.empty())
  24. {
  25. int u=q.front(); q.pop();
  26. for(int i=1;i<=num;i++) if(!a[i] && map[u][i]>flow[u][i])
  27. {
  28. fa[i]=u; q.push(i);
  29. a[i]=MIN(a[u],map[u][i]-flow[u][i]);
  30. }
  31. }
  32. if(a[t]==0) break;
  33. for(int u=t;u!=s;u=fa[u])
  34. {
  35. flow[fa[u]][u]+=a[t];
  36. flow[u][fa[u]]-=a[t];
  37. }
  38. ans+=a[t];
  39. }
  40. return ans;
  41. }
  42. int main()
  43. {
  44. int i,j,n,m,t,a,b,c;
  45. scanf("%d",&t);
  46. for(j=1;j<=t;j++)
  47. {
  48. memset(map,0,sizeof(map));
  49. scanf("%d%d",&n,&m);
  50. for(i=0;i<m;i++)
  51. {
  52. scanf("%d%d%d",&a,&b,&c);
  53. map[a][b]+=c;
  54. }
  55. int ans=maxflow(n,map,1,n);
  56. printf("Case %d: %d\n",j,ans);
  57. }
  58. return 0;
  59. }

好了,网络流的诸多算法终于搞定一个,接下来 改进的SAP算法。。。时间不多,加油了cxb !

读书人网 >编程

热点推荐