[关闭]
@lpf20051024 2020-08-11T14:51:04.000000Z 字数 9166 阅读 695

网络流 24 题

网络流 题解


前言

都是从 cnblog 来的吧,代码就贴在这里啦。

配合 原讲解+少量注释 食用更佳。

飞行员配对方案问题

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<iostream>
  5. #include<cmath>
  6. #include<queue>
  7. #define N 110
  8. #define M 100100
  9. using namespace std;
  10. int n,m,head[N],match[N],cnt=0,ans=0;
  11. bool vis[N];
  12. struct Edge{
  13. int nxt,to;
  14. }ed[M];
  15. int read(){
  16. int x=0,f=1;char c=getchar();
  17. while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
  18. while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
  19. return x*f;
  20. }
  21. void add(int u,int v){
  22. ed[++cnt].nxt=head[u];
  23. ed[cnt].to=v;
  24. head[u]=cnt;
  25. return;
  26. }
  27. bool dfs(int u){
  28. for(int i=head[u];i;i=ed[i].nxt){
  29. int v=ed[i].to;
  30. if(vis[v]) continue;
  31. vis[v]=true;
  32. if(!match[v] || dfs(match[v])){
  33. match[v]=u;return true;
  34. }
  35. }
  36. return false;
  37. }
  38. int main(){
  39. n=read(),m=read()-n;
  40. int u=read(),v=read();
  41. while(u!=-1 && v!=-1){
  42. add(u,v),add(v,u);
  43. u=read(),v=read();
  44. }
  45. for(int i=1;i<=n;i++){
  46. memset(vis,false,sizeof(vis));
  47. if(dfs(i)) ++ans;
  48. }
  49. printf("%d\n",ans);
  50. for(int i=n+1;i<=n+m;i++)
  51. if(match[i]) printf("%d %d\n",match[i],i);
  52. return 0;
  53. }

圆桌问题

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<cmath>
  4. #include<iostream>
  5. #include<algorithm>
  6. #include<queue>
  7. #define N 1010
  8. #define M 100010
  9. #define INF 0x3f3f3f3f
  10. using namespace std;
  11. int n,m,s,t,sum=0,head[N],d[N],cnt=1;
  12. struct Edge{
  13. int nxt,to,val;
  14. }ed[M<<1];
  15. queue<int>q;
  16. int read(){
  17. int x=0,f=1;char c=getchar();
  18. while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
  19. while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
  20. return x*f;
  21. }
  22. void add(int u,int v,int w){
  23. ed[++cnt].nxt=head[u];ed[cnt].to=v;ed[cnt].val=w;head[u]=cnt;
  24. ed[++cnt].nxt=head[v];ed[cnt].to=u;ed[cnt].val=0;head[v]=cnt;
  25. }
  26. bool bfs(){
  27. memset(d,0,sizeof(d));
  28. while(!q.empty()) q.pop();
  29. d[s]=1;q.push(s);
  30. while(!q.empty()){
  31. int u=q.front();q.pop();
  32. for(int i=head[u];i;i=ed[i].nxt){
  33. int v=ed[i].to,w=ed[i].val;
  34. if(w && !d[v]){
  35. d[v]=d[u]+1;
  36. if(v==t) return true;
  37. q.push(v);
  38. }
  39. }
  40. }
  41. return false;
  42. }
  43. int dinic(int u,int flow){
  44. if(u==t) return flow;
  45. int rest=flow;
  46. for(int i=head[u];i && rest;i=ed[i].nxt){
  47. int v=ed[i].to,w=ed[i].val;
  48. if(w && d[v]==d[u]+1){
  49. int k=dinic(v,min(rest,w));
  50. if(!k) d[v]=0;
  51. ed[i].val-=k;
  52. ed[i^1].val+=k;
  53. rest-=k;
  54. }
  55. }
  56. return flow-rest;
  57. }
  58. int main(){
  59. n=read(),m=read();
  60. s=0,t=n+m+1;
  61. for(int i=1;i<=n;i++){
  62. int a=read();sum+=a;//记录代表总数。
  63. add(s,i,a);
  64. }
  65. for(int i=1;i<=m;i++){
  66. int a=read();
  67. add(i+n,t,a);
  68. }
  69. for(int i=1;i<=n;i++)
  70. for(int j=1;j<=m;j++)
  71. add(i,j+n,1);
  72. int ans=0,flow;
  73. while(bfs())
  74. if(flow=dinic(s,INF)) ans+=flow;
  75. if(ans<sum){puts("0");return 0;}
  76. puts("1");
  77. for(int u=1;u<=n;u++){
  78. for(int i=head[u];i;i=ed[i].nxt){
  79. int v=ed[i].to,w=ed[i].val;
  80. if(v!=s && !w) printf("%d ",v-n);//根据残量网络输出。
  81. }
  82. puts("");
  83. }
  84. return 0;
  85. }

最小路径覆盖问题

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<cmath>
  4. #include<algorithm>
  5. #include<iostream>
  6. #include<queue>
  7. #define N 510
  8. #define M 100010
  9. #define INF 0x3f3f3f3f
  10. using namespace std;
  11. int n,m,s,t,head[N],fa[N],d[N],cnt=1;
  12. struct Edge{
  13. int nxt,frm,to,val;
  14. }ed[M];
  15. queue<int>q;
  16. int read(){
  17. int x=0,f=1;char c=getchar();
  18. while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
  19. while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
  20. return x*f;
  21. }
  22. void add(int u,int v,int w){
  23. ed[++cnt]=(Edge){head[u],u,v,w};head[u]=cnt;
  24. ed[++cnt]=(Edge){head[v],v,u,0};head[v]=cnt;
  25. }
  26. void build(){//建图。
  27. n=read(),m=read();
  28. s=0,t=n<<1|1;
  29. for(int i=1;i<=m;i++){
  30. int u=read(),v=read();
  31. add(u,v+n,1);
  32. }
  33. for(int i=1;i<=n;i++) add(s,i,1);
  34. for(int i=1;i<=n;i++) add(i+n,t,1);
  35. return;
  36. }
  37. bool bfs(){
  38. while(!q.empty()) q.pop();
  39. memset(d,0,sizeof(d));
  40. d[s]=1;q.push(s);
  41. while(!q.empty()){
  42. int u=q.front();q.pop();
  43. for(int i=head[u];i;i=ed[i].nxt){
  44. int v=ed[i].to,w=ed[i].val;
  45. if(w && !d[v]){
  46. d[v]=d[u]+1;
  47. if(v==t) return true;
  48. q.push(v);
  49. }
  50. }
  51. }
  52. return false;
  53. }
  54. int Dinic(int u,int flow){
  55. if(u==t) return flow;
  56. int rest=flow;
  57. for(int i=head[u];i && rest;i=ed[i].nxt){
  58. int v=ed[i].to,w=ed[i].val;
  59. if(w && d[v]==d[u]+1){
  60. int k=Dinic(v,min(rest,w));
  61. if(!k) d[v]=0;
  62. ed[i].val-=k;
  63. ed[i^1].val+=k;
  64. rest-=k;
  65. }
  66. }
  67. return flow-rest;
  68. }
  69. int find(int x){
  70. if(fa[x]==x) return x;
  71. return fa[x]=find(fa[x]);
  72. }
  73. void Print(int u){
  74. printf("%d ",u);
  75. for(int i=head[u];i;i=ed[i].nxt)
  76. if(!ed[i].val && ed[i].to>n)
  77. Print(ed[i].to-n);//递归输出。
  78. return;
  79. }
  80. void work(){
  81. int flow,ans=0;
  82. while(bfs())
  83. if(flow=Dinic(s,INF)) ans+=flow;
  84. for(int i=1;i<=n;i++) fa[i]=i;
  85. for(int i=2;i<=cnt;i++){
  86. int u=ed[i].frm,v=ed[i].to,w=ed[i].val;
  87. if(u>s && u<=n && v>n && v<t && !w)//找到被匹配了的边,表示这两点被合并了。
  88. fa[find(v-n)]=find(u);
  89. //与一般并查集不同的是 v-n 和 u 的顺序不可调换。
  90. //因为 u 在路径上的位置必然在 v-n 之前,而路径的输出需要考虑递归的顺序。
  91. }
  92. for(int i=1;i<=n;i++)
  93. if(fa[i]==i) Print(i),puts("");
  94. printf("%d\n",n-ans);
  95. return;
  96. }
  97. int main(){
  98. build();
  99. work();
  100. return 0;
  101. }

试题库问题

  1. //真就是一道挺板子的题目啊。
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<iostream>
  5. #include<cmath>
  6. #include<algorithm>
  7. #include<queue>
  8. #define N 10010
  9. #define M 200010
  10. #define INF 0x3f3f3f3f
  11. using namespace std;
  12. int m,n,s,t,head[N],d[N],cnt=1;
  13. struct Edge{
  14. int nxt,to,val;
  15. }ed[M];
  16. queue<int>q;
  17. int read(){
  18. int x=0,f=1;char c=getchar();
  19. while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
  20. while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
  21. return x*f;
  22. }
  23. void add(int u,int v,int w){
  24. ed[++cnt]=(Edge){head[u],v,w};head[u]=cnt;
  25. ed[++cnt]=(Edge){head[v],u,0};head[v]=cnt;
  26. return;
  27. }
  28. bool bfs(){
  29. while(!q.empty()) q.pop();
  30. memset(d,0,sizeof(d));
  31. d[s]=1;q.push(s);
  32. while(!q.empty()){
  33. int u=q.front();q.pop();
  34. for(int i=head[u];i;i=ed[i].nxt){
  35. int v=ed[i].to,w=ed[i].val;
  36. if(w && !d[v]){
  37. d[v]=d[u]+1;
  38. if(v==t) return true;
  39. q.push(v);
  40. }
  41. }
  42. }
  43. return false;
  44. }
  45. int Dinic(int u,int flow){
  46. if(u==t) return flow;
  47. int rest=flow;
  48. for(int i=head[u];i && rest;i=ed[i].nxt){
  49. int v=ed[i].to,w=ed[i].val;
  50. if(w && d[v]==d[u]+1){
  51. int k=Dinic(v,min(rest,w));
  52. if(!k) d[v]=0;
  53. ed[i].val-=k;
  54. ed[i^1].val+=k;
  55. rest-=k;
  56. }
  57. }
  58. return flow-rest;
  59. }
  60. int main(){
  61. n=read(),m=read();
  62. int a,b,sum=0;
  63. s=0,t=n+m+1;
  64. for(int i=1;i<=n;i++)
  65. a=read(),sum+=a,add(s,i,a);
  66. for(int i=1;i<=m;i++){
  67. a=read();
  68. while(a--) b=read(),add(b,i+n,1);
  69. }
  70. for(int i=1;i<=m;i++)
  71. add(i+n,t,1);
  72. int ans=0,flow;
  73. while(bfs())
  74. if(flow=Dinic(s,INF)) ans+=flow;
  75. if(ans<sum){
  76. puts("No Solution!");return 0;
  77. }
  78. for(int u=1;u<=n;u++){
  79. printf("%d: ",u);
  80. for(int i=head[u];i;i=ed[i].nxt)
  81. if(!ed[i].val && ed[i].to>n) printf("%d ",ed[i].to-n);
  82. puts("");
  83. }
  84. return 0;
  85. }

魔术球问题

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<algorithm>
  5. #include<queue>
  6. #include<cmath>
  7. #define N 1000010
  8. #define M 2000010
  9. #define s 0
  10. #define t 1000000
  11. #define INF 0x3f3f3f3f
  12. using namespace std;
  13. int n,head[N],frs[N],pre[N],d[N],cnt=1;
  14. bool vis[N];
  15. struct Edge{
  16. int nxt,to,val;
  17. }ed[M];
  18. queue<int>q;
  19. int read(){
  20. int x=0,f=1;char c=getchar();
  21. while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
  22. while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
  23. return x*f;
  24. }
  25. void add(int u,int v,int w){
  26. ed[++cnt]=(Edge){head[u],v,w};head[u]=cnt;
  27. ed[++cnt]=(Edge){head[v],u,0};head[v]=cnt;
  28. return;
  29. }
  30. bool bfs(){
  31. while(!q.empty()) q.pop();
  32. memset(d,0,sizeof(d));
  33. d[s]=1;q.push(s);
  34. while(!q.empty()){
  35. int u=q.front();q.pop();
  36. for(int i=head[u];i;i=ed[i].nxt){
  37. int v=ed[i].to,w=ed[i].val;
  38. if(w && !d[v]){
  39. d[v]=d[u]+1;
  40. if(v==t) return true;
  41. q.push(v);
  42. }
  43. }
  44. }
  45. return false;
  46. }
  47. int Dinic(int u,int flow){
  48. if(u==t) return flow;
  49. int rest=flow;
  50. for(int i=head[u];i && rest;i=ed[i].nxt){
  51. int v=ed[i].to,w=ed[i].val;
  52. if(w && d[v]==d[u]+1){
  53. int k=Dinic(v,min(w,rest));
  54. if(!k) d[v]=0;
  55. ed[i].val-=k;
  56. ed[i^1].val+=k;
  57. rest-=k;
  58. pre[u>>1]=v>>1;
  59. //开始建图时乘 2 了。
  60. //很巧的是 (u<<1)>>1=(u<<1|1)>>1=u。
  61. }
  62. }
  63. return flow-rest;
  64. }
  65. int main(){
  66. n=read();
  67. int now=0,Pillar=0;
  68. while(Pillar<=n){//如果柱子数 > n 就退出。
  69. ++now;
  70. add(s,now<<1,1);//和源点连接。
  71. add(now<<1|1,t,1);//和汇点连接。
  72. for(int i=sqrt(now)+1;i*i<(now<<1);i++)//和比自己小的能与自己组成完全平方数的数连边。
  73. add((i*i-now)<<1,now<<1|1,1);//注意细节。
  74. int flow,ans=0;
  75. while(bfs())
  76. if(flow=Dinic(s,INF)) ans+=flow;
  77. if(!ans)//如果找不到增广路。
  78. frs[++Pillar]=now;
  79. }
  80. printf("%d\n",--now);//记得减 1,因为最后的球肯定是放在第 n+1 个柱子上的。
  81. memset(vis,false,sizeof(vis));
  82. for(int i=1;i<=n;i++){
  83. if(vis[frs[i]]) continue;//如果之前见过你了就不用输出了。
  84. for(int u=frs[i];u && u!=(t>>1);u=pre[u])
  85. vis[u]=true,printf("%d ",u);
  86. puts("");
  87. }
  88. return 0;
  89. }

星际转移问题

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<iostream>
  4. #include<cmath>
  5. #include<algorithm>
  6. #include<cstdlib>
  7. #define N 1000010
  8. #define M 2000010
  9. #define P 110
  10. #define s 0
  11. #define t N-10
  12. #define INF 0x3f3f3f3f
  13. using namespace std;
  14. int n,m,k,ans,head[N],cnt=1;
  15. int d[N];
  16. int r[P],g[P][P],h[P];
  17. int fa[P],q[N];
  18. struct Edge{
  19. int nxt,to,val;
  20. }ed[M];
  21. int read(){
  22. int x=0,f=1;char c=getchar();
  23. while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();
  24. while(c>='0' && c<='9') x=x*10+c-48,c=getchar();
  25. return x*f;
  26. }
  27. void init(){
  28. n=read(),m=read(),k=read();
  29. for(int i=1;i<=m;i++){
  30. h[i]=read(),r[i]=read();
  31. for(int j=0;j<r[i];j++) g[i][j]=read();
  32. }
  33. return;
  34. }
  35. int find(int x){
  36. if(fa[x]==x) return x;
  37. return fa[x]=find(fa[x]);
  38. }
  39. void merge(int x,int y){
  40. int fx=find(x);
  41. int fy=find(y);
  42. if(fx!=fy) fa[fx]=fy;
  43. return;
  44. }
  45. void pre_chck(){
  46. for(int i=1;i<=n+2;i++) fa[i]=i;
  47. for(int i=1;i<=m;i++)
  48. for(int j=0;j<r[i];j++){
  49. if(g[i][j]==0) g[i][j]=n+1;
  50. if(g[i][j]==-1) g[i][j]=n+2;
  51. if(j!=0) merge(g[i][j],g[i][j-1]);
  52. }
  53. if(find(n+1)!=find(n+2)){puts("0");exit(0);}
  54. return;
  55. }
  56. void add(int u,int v,int w){
  57. ed[++cnt]=(Edge){head[u],v,w};head[u]=cnt;
  58. ed[++cnt]=(Edge){head[v],u,0};head[v]=cnt;
  59. return;
  60. }
  61. bool bfs(){
  62. for(int i=1;i<=ans*(n+1);i++) d[i]=0;//千万别用 memset。
  63. d[t]=0;
  64. d[s]=1;q[1]=s;
  65. int h=1,tail=1;
  66. while(h<=tail){
  67. int u=q[h];++h;
  68. for(int i=head[u];i;i=ed[i].nxt){
  69. int v=ed[i].to,w=ed[i].val;
  70. if(w && !d[v]){
  71. d[v]=d[u]+1;
  72. if(v==t) return true;
  73. q[++tail]=v;
  74. }
  75. }
  76. }
  77. return false;
  78. }
  79. int Dinic(int u,int flow){
  80. if(u==t) return flow;
  81. int i,rest=0;
  82. for(i=head[u];i;i=ed[i].nxt){
  83. int v=ed[i].to,w=ed[i].val;
  84. if(w && d[v]==d[u]+1){
  85. int k=Dinic(v,min(flow-rest,w));
  86. if(!k) d[v]=0;
  87. ed[i].val-=k;
  88. ed[i^1].val+=k;
  89. rest+=k;
  90. if(rest==flow) return rest;
  91. }
  92. }
  93. return rest;
  94. }
  95. int main(){
  96. init();
  97. pre_chck();//并查集判无解。
  98. int now=0;
  99. for(ans=1;;ans++){
  100. add(s,ans*(n+1),INF);
  101. for(int i=1;i<=m;i++){
  102. int x=(ans-1)%r[i],y=ans%r[i];
  103. if(g[i][x]==n+2) x=t;
  104. else x=(ans-1)*(n+1)+g[i][x];
  105. if(g[i][y]==n+2) y=t;
  106. else y=ans*(n+1)+g[i][y];
  107. add(x,y,h[i]);
  108. }//日常建边。
  109. while(bfs()) now+=Dinic(s,INF);//利用残量网络跑 Dinic。
  110. if(now>=k){printf("%d\n",ans);return 0;}
  111. for(int i=1;i<=n+1;i++)
  112. add((ans-1)*(n+1)+i,ans*(n+1)+i,INF);//向下一层转移。
  113. }
  114. return 0;
  115. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注