(还是不熟 好难啊
最大流裸题
Edmonds_Karp算法(bfs)
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; int m; int g[220][220],pre[220];int bfs(int st,int ed) { for(int i=1;i<=m;i++)pre[i]=-1; int u,w=inf; queue<int>que; que.push(st);pre[st]=0; while(!que.empty()) { u=que.front();que.pop(); if(u==ed)break; for(int i=1;i<=m;i++) { if(pre[i]==-1&&g[u][i]>0) { pre[i]=u; w=min(w,g[u][i]); que.push(i); } } } if(pre[ed]==-1)return 0; return w; } int E_K(int st,int ed) { int w,sum=0; while(w=bfs(st,ed)) { int u=ed; while(u!=st) { g[pre[u]][u]-=w; g[u][pre[u]]+=w; u=pre[u]; } sum+=w; } return sum; } int main() { int n,i,j,k,u,v,w; while(~scanf("%d%d",&n,&m)) { memset(g,0,sizeof(g)); for(i=1;i<=n;i++) { scanf("%d%d%d",&u,&v,&w); g[u][v]+=w; } printf("%d ",E_K(1,m)); } } Dinic算法 (是E_K算法的优化 可以快一些 (bfs+dfs)) #include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; int m; int g[220][220],dep[220]; bool bfs(int st,int ed) { for(int i=1;i<=m;i++)dep[i]=-1; int u; queue<int>que; que.push(st);dep[st]=0; while(!que.empty()) { u=que.front();que.pop(); for(int i=1;i<=m;i++) { if(dep[i]==-1&&g[u][i]>0) { dep[i]=dep[u]+1; if(i==ed)return 1; que.push(i); } } } return dep[ed]!=-1; } int dfs(int st,int ed,int lim) { if(!lim||st==ed)return lim; int w=0,d; for(int i=1;i<=m;i++) { if(dep[i]==dep[st]+1&&g[st][i]>0&&(d=dfs(i,ed,min(g[st][i],lim)))) { g[st][i]-=d; g[i][st]+=d; w+=d; lim-=d; if(!lim)break; } } return w; } int Dinic(int st,int ed) { int sum=0; while(bfs(st,ed))sum+=dfs(st,ed,inf); return sum; } int main() { int n,i,j,k,u,v,w; while(~scanf("%d%d",&n,&m)) { memset(g,0,sizeof(g)); for(i=1;i<=n;i++) { scanf("%d%d%d",&u,&v,&w); g[u][v]+=w; } printf("%d ",Dinic(1,m)); } }
LOJ「网络流 24 题」搭配飞行员 (第一题
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; int n,m; int g[110][110],dep[110]; bool bfs(int st,int ed) { for(int i=0;i<=n;i++)dep[i]=-1; int u; queue<int>que; que.push(st);dep[st]=0; while(!que.empty()) { u=que.front();que.pop(); for(int i=1;i<=n;i++) { if(dep[i]==-1&&g[u][i]>0) { dep[i]=dep[u]+1; if(i==ed)return 1; que.push(i); } } } return dep[ed]!=-1; } int dfs(int st,int ed,int lim) { if(!lim||st==ed)return lim; int w=0,d; for(int i=0;i<=n;i++) { if(dep[i]==dep[st]+1&&g[st][i]>0&&(d=dfs(i,ed,min(g[st][i],lim)))) { g[st][i]-=d; g[i][st]+=d; w+=d; lim-=d; if(!lim)break; } } return w; } int Dinic(int st,int ed) { int sum=0; while(bfs(st,ed))sum+=dfs(st,ed,inf); return sum; } int main() { int i,j,k,u,v; scanf("%d%d",&n,&m); // scanf("%d",&k); for(i=1;i<=m;i++)g[0][i]=1; for(i=m+1;i<=n;i++)g[i][n+1]=1; n++; // while(k--) while(~scanf("%d%d",&u,&v)) { // scanf("%d%d",&u,&v); g[u][v]=1; } printf("%d ",Dinic(0,n)); }
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; int n,m; int g[110][110],dep[110]; bool bfs(int st,int ed) { for(int i=0;i<=n;i++)dep[i]=-1; int u; queue<int>que; que.push(st);dep[st]=0; while(!que.empty()) { u=que.front();que.pop(); for(int i=1;i<=n;i++) { if(dep[i]==-1&&g[u][i]>0) { dep[i]=dep[u]+1; if(i==ed)return 1; que.push(i); } } } return dep[ed]!=-1; } int dfs(int st,int ed,int lim) { if(!lim||st==ed)return lim; int w=0,d; for(int i=0;i<=n;i++) { if(dep[i]==dep[st]+1&&g[st][i]>0&&(d=dfs(i,ed,min(g[st][i],lim)))) { g[st][i]-=d; g[i][st]+=d; w+=d; lim-=d; if(!lim)break; } } return w; } int Dinic(int st,int ed) { int sum=0; while(bfs(st,ed))sum+=dfs(st,ed,inf); return sum; } int main() { int i,j,k,u,v; scanf("%d%d",&m,&n); for(i=1;i<=m;i++)g[0][i]=1; for(i=m+1;i<=n;i++)g[i][n+1]=1; n++; scanf("%d%d",&u,&v); while(u!=-1&&v!=-1) { g[u][v]=1; scanf("%d%d",&u,&v); } k=Dinic(0,n); if(k==0)puts("No solution!"); else { printf("%d ",k); for(i=1;i<=m;i++) { for(j=m+1;j<=n;j++) if(g[j][i]!=0)printf("%d %d ",i,j); } } }
好艰难 我觉得我只会 对着模板抄
求最大流量下的最小费用
(为了xxxxxx,尝试用链式前向星来做,还不太习惯)
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; struct P{ int to,flow,dis,next; }p[50500<<1]; int head[50500<<1],pnum; void add(int from,int to,int flow,int dis) { p[++pnum].next=head[from]; p[pnum].to=to; p[pnum].flow=flow; p[pnum].dis=dis; head[from]=pnum; } int dis[5050],vis[5050],pre[5050],last[5050],flow[5050]; bool spaf_bfs(int s,int t) { memset(dis,inf,sizeof(dis)); memset(vis,0,sizeof(vis)); memset(flow,inf,sizeof(flow)); queue<int> que; que.push(s);dis[s]=0;pre[t]=-1;vis[s]=1; while(!que.empty()) { int u=que.front();que.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=p[i].next) { if(p[i].flow>0&&dis[p[i].to]>dis[u]+p[i].dis) { dis[p[i].to]=dis[u]+p[i].dis; pre[p[i].to]=u; last[p[i].to]=i; flow[p[i].to]=min(flow[u],p[i].flow); if(!vis[p[i].to]) { vis[p[i].to]=1; que.push(p[i].to); } } } } return pre[t]!=-1; } void solve(int s,int t,int &w,int &c) { w=0;c=0; while(spaf_bfs(s,t)) { int u=t; w+=flow[t]; c+=flow[t]*dis[t]; while(u!=s) { p[last[u]].flow-=flow[t]; p[last[u]^1].flow+=flow[t]; u=pre[u]; } } } int main() { memset(head,-1,sizeof(head));pnum=-1; int n,m,s,t,i,u,v,w,f; scanf("%d%d%d%d",&n,&m,&s,&t); for(i=1;i<=m;i++) { scanf("%d%d%d%d",&u,&v,&w,&f); add(u,v,w,f); add(v,u,0,-f); } solve(s,t,u,v); printf("%d %d ",u,v); }
最大流+二分
借着别人的博客的二分 总算补完了这一题。
对二分求最小/最大值技巧还不太熟。一直没能想到。
(用E_K算法会超时,用Dinic不会)
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; struct P{ int next,to,flow; }p[22200<<1]; int head[22200<<1],pnum; struct PP{ int u,v,t; PP(){} PP(int uu,int vv,int tt){u=uu;v=vv;t=tt;} }pp[20200]; void add(int from,int to,int flow) { p[++pnum].next=head[from]; p[pnum].to=to; p[pnum].flow=flow; head[from]=pnum; } int x,y,c,n,allsum,a[2020],b[2020]; int pre[2020],dep[2020]; bool vis[2020]; bool bfs(int st,int ed) { memset(dep,-1,sizeof(dep)); int u; queue<int>que; que.push(st);dep[st]=0; while(!que.empty()) { u=que.front();que.pop(); for(int i=head[u];i!=-1;i=p[i].next) { if(dep[p[i].to]==-1&&p[i].flow) { dep[p[i].to]=dep[u]+1; if(p[i].to==ed)return 1; que.push(p[i].to); } } } return dep[ed]!=-1; } int dfs(int st,int ed,int lim) { if(!lim||st==ed)return lim; int w=0,d; for(int i=head[st];i!=-1;i=p[i].next) { if(dep[p[i].to]==dep[st]+1&&(d=dfs(p[i].to,ed,min(p[i].flow,lim)))) { p[i].flow-=d; p[i^1].flow+=d; w+=d; lim-=d; if(!lim)break; } } return w; } int Dinic(int st,int ed) { int sum=0; while(bfs(st,ed))sum+=dfs(st,ed,inf); return sum; } /* int bfs(int st,int ed) { memset(vis,0,sizeof(vis)); int u,w=inf; queue<int>que; que.push(st);pre[st]=pre[ed]=-1;vis[st]=1; while(!que.empty()) { u=que.front();que.pop(); if(u==ed)break; for(int i=head[u];i!=-1;i=p[i].next) { if(vis[p[i].to]==0&&p[i].flow>0) { vis[p[i].to]=1; pre[p[i].to]=i; w=min(w,p[i].flow); que.push(p[i].to); } } } if(pre[ed]==-1)return 0; return w; } int E_K(int st,int ed) { int w,sum=0; while(w=bfs(st,ed)) { for(int i=pre[ed];i!=-1;i=pre[p[i^1].to]) { p[i].flow-=w; p[i^1].flow+=w; } sum+=w; } return sum; }*/ bool check(int mid) { int i; memset(head,-1,sizeof(head));pnum=-1; for(i=1;i<=y;i++) { add(0,i,a[i]); add(i,0,0); } for(i=1;i<=x;i++) { add(y+i,n,b[i]); add(n,y+i,0); } for(i=1;i<=c;i++) { if(pp[i].t<=mid) { add(pp[i].u,pp[i].v+y,inf); add(pp[i].v+y,pp[i].u,0); } } int maxflow=Dinic(0,n); if(maxflow==allsum)return 1; return 0; } int main() { allsum=0; int i,j,k,w; int u,v,t,l,r=0,mid,ans; scanf("%d%d%d",&x,&y,&c); n=x+y+1; for(i=1;i<=x;i++) { scanf("%d",&b[i]); allsum+=b[i]; } for(i=1;i<=y;i++)scanf("%d",&a[i]); for(i=1;i<=c;i++) { scanf("%d%d%d",&v,&u,&t); pp[i]=PP(u,v,t); r=max(r,t); } l=0;ans=-1;r++; while(l<r) { mid=(l+r)>>1; if(check(mid)) { ans=mid; r=mid; } else l=mid+1; } printf("%d ",ans); }
LOJ 「网络流 24 题」太空飞行计划 (第二题
1.初学网络流,从这道题的洛谷题解知道了一件事:
Dinic最后一次bfs的dep(深度)数组标记了与源点连通的点(即,未被初始化标记的点 就是 与最终确定与源点连通的点),有利于最后方案的输出。
下一题告诉我这是假的QAQ。。所以通用方法是什么/(ㄒoㄒ)/~~
2.据说 这道题是最小割的题。我用最大流做的,不懂为什么是最小割?
因为:最小割==最大流
有趣的是:一直想不到,正确建图后,总的利润-最大流的花费 会等于 最大盈利。但是按这道题的正确建图方法去思考,正好是这样!
3.这道题,据说:
这道题数据是在windows生成的,输入数据中所有的换行都是'
'而不是'
'
读入某实验需要用到的仪器编号的时候,可以这么读入
char tools[10000]; memset(tools,0,sizeof tools); cin.getline(tools,10000); int ulen=0,tool; while (sscanf(tools+ulen,"%d",&tool)==1)//之前已经用scanf读完了赞助商同意支付该实验的费用 {//tool是该实验所需仪器的其中一个 //这一行,你可以将读进来的编号进行储存、处理,如连边。 if (tool==0) ulen++; else { while (tool) { tool/=10; ulen++; } } ulen++; }
代码:
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=3e3+50; struct P{ int to,flow,next; }p[maxn]; int head[maxn],pnum; void add(int from,int to,int flow) { p[++pnum].next=head[from]; p[pnum].to=to; p[pnum].flow=flow; head[from]=pnum; } int dis[maxn],vis[maxn],dep[maxn],flow[maxn]; bool bfs(int st,int ed) { memset(dep,-1,sizeof(dep)); int u; queue<int>que; que.push(st);dep[st]=0; while(!que.empty()) { u=que.front();que.pop(); for(int i=head[u];i!=-1;i=p[i].next) { if(dep[p[i].to]==-1&&p[i].flow) { dep[p[i].to]=dep[u]+1; if(p[i].to==ed)return 1; que.push(p[i].to); } } } return dep[ed]!=-1; } int dfs(int st,int ed,int lim) { if(!lim||st==ed)return lim; int w=0,d; for(int i=head[st];i!=-1;i=p[i].next) { if(dep[p[i].to]==dep[st]+1&&p[i].flow&&(d=dfs(p[i].to,ed,min(p[i].flow,lim)))) { p[i].flow-=d; p[i^1].flow+=d; w+=d; lim-=d; if(!lim)break; } } return w; } int Dinic(int st,int ed) { int sum=0; while(bfs(st,ed))sum+=dfs(st,ed,inf); return sum; } //这道题数据是在windows生成的 //输入数据中所有的换行都是' '而不是' ' int main() { memset(head,-1,sizeof(head));pnum=-1; int m,n,i,j,k,w,ed,sum=0,ans; scanf("%d%d",&m,&n); ed=m+n+1; char tools[10000];// for(i=1;i<=m;i++) { scanf("%d",&w); sum+=w; add(0,i,w); add(i,0,0); memset(tools,0,sizeof tools); cin.getline(tools,10000); int ulen=0,tool; while (sscanf(tools+ulen,"%d",&tool)==1)//之前已经用scanf读完了赞助商同意支付该实验的费用 {//tool是该实验所需仪器的其中一个 add(i,m+tool,inf); add(m+tool,i,0);//这一行,你可以将读进来的编号进行储存、处理,如连边。 if (tool==0) ulen++; else { while (tool) { tool/=10; ulen++; } } ulen++; } } for(i=1;i<=n;i++) { scanf("%d",&w); add(m+i,ed,w); add(ed,m+i,0); } ans=sum-Dinic(0,ed); for(i=1,k=0;i<=m;i++) { if(dep[i]!=-1) { if(k)putchar(32); k=1; printf("%d",i); } } putchar(10); for(i=m+1,k=0;i<ed;i++) { if(dep[i]!=-1) { if(k)putchar(32); k=1; printf("%d",i-m); } } putchar(10); printf("%d ",ans); }
路径输出是一个问题啊。本来以为用if(dep[i]!=-1)来找就行了,结果发现是假的
这道题由于流量只是1,所以就用if(p[i].w==0&&i&1==0)来找,但是如果流量等于2,3,4....n呢?QAQ
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=6e3+5; struct P{ int to,w,next; }p[maxn<<2]; int head[355],cnt; void add(int u,int v,int w) { p[cnt].to=v; p[cnt].w=w; p[cnt].next=head[u]; head[u]=cnt++; } int n; int dep[355]; bool bfs(int st,int ed) { memset(dep,-1,sizeof(dep)); int u; queue<int>que; que.push(st);dep[st]=0; while(!que.empty()) { u=que.front();que.pop(); for(int i=head[u];i!=-1;i=p[i].next) { if(dep[p[i].to]==-1&&p[i].w) { dep[p[i].to]=dep[u]+1; if(p[i].to==ed)return 1; que.push(p[i].to); } } } return dep[ed]!=-1; } int dfs(int st,int ed,int lim) { if(!lim||st==ed)return lim; int w=0,d; for(int i=head[st];i!=-1;i=p[i].next) { if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim)))) { p[i].w-=d; p[i^1].w+=d; w+=d; lim-=d; if(!lim)break; } } return w; } int Dinic(int st,int ed) { int sum=0; while(bfs(st,ed))sum+=dfs(st,ed,inf); return sum; } int son[335]; bool isson[335]; void getline() { int u,v,f; for(u=1;u<=n;u++) { f=u; for(int i=head[u];i!=-1;i=p[i].next) { if(p[i].w||i&1)continue; v=p[i].to; if(v>n)v-=n; son[f]=v;f=v; isson[v]=1; p[i].w=-1; } } } int main() { memset(head,-1,sizeof(head)); int m,i,u,v,ed,res; scanf("%d%d",&n,&m);ed=n*2+1; for(i=1;i<=n;i++) { add(0,i,1);add(i,0,0); add(i+n,ed,1);add(ed,i+n,0); } for(i=1;i<=m;i++) { scanf("%d%d",&u,&v); add(u,n+v,1);add(n+v,u,0); } res=n-Dinic(0,ed); getline(); for(i=1;i<=n;i++) { if(isson[i])continue; u=i; printf("%d ",u); while(son[u]) { u=son[u]; printf("%d ",u); } printf(" "); } printf("%d ",res); }
然后
这个可以化为最小路径覆盖问题。用上面的代码输出路径。
(要不是放在网络流里,这怎么可能想到嘛)
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=7e4+5; struct P{ int to,w,next; }p[maxn<<2]; int head[maxn],cnt; void add(int u,int v,int w) { p[cnt].to=v; p[cnt].w=w; p[cnt].next=head[u]; head[u]=cnt++; } int n; int dep[maxn]; bool bfs(int st,int ed) { memset(dep,-1,sizeof(dep)); int u; queue<int>que; que.push(st);dep[st]=0; while(!que.empty()) { u=que.front();que.pop(); for(int i=head[u];i!=-1;i=p[i].next) { if(dep[p[i].to]==-1&&p[i].w) { dep[p[i].to]=dep[u]+1; if(p[i].to==ed)return 1; que.push(p[i].to); } } } return dep[ed]!=-1; } int dfs(int st,int ed,int lim) { if(!lim||st==ed)return lim; int w=0,d; for(int i=head[st];i!=-1;i=p[i].next) { if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim)))) { p[i].w-=d; p[i^1].w+=d; w+=d; lim-=d; if(!lim)break; } } return w; } int Dinic(int st,int ed) { int sum=0; while(bfs(st,ed))sum+=dfs(st,ed,inf); return sum; } int son[maxn]; bool isson[maxn]; void getline() { int u,v,f; for(u=1;u<=n;u++) { f=u; for(int i=head[u];i!=-1;i=p[i].next) { if(p[i].w||i&1)continue; v=p[i].to; if(v>n)v-=n; son[f]=v;f=v; isson[v]=1; p[i].w=-1; } } } void addedge(int k) { for(int i=1;i<=k;i++) { int up=i*i; for(int j=1;j<<1<=up;j++) { if(up-j>n)continue; if(j<<1==up)break; add(j,up-j+n,1); add(up-j+n,j,0); } } } int main() { memset(head,-1,sizeof(head)); int i,k,u,v,ed,res; scanf("%d",&k); n=(k+1)*(k+1)/2-1; ed=n*2+1; for(i=1;i<=n;i++) { add(0,i,1);add(i,0,0); add(i+n,ed,1);add(ed,i+n,0); } addedge(k); Dinic(0,ed); printf("%d ",n); getline(); for(i=1;i<=n;i++) { if(isson[i])continue; u=i; printf("%d",u); while(son[u]) { u=son[u]; printf(" %d",u); } printf(" "); } }
满流的路径输出是那个流最后为零,那么它就与源点连通。
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=5e4+5; struct P{ int to,w,next; }p[maxn<<2]; int head[maxn],cnt; void add(int u,int v,int w) { p[cnt].to=v; p[cnt].w=w; p[cnt].next=head[u]; head[u]=cnt++; } int n; int dep[455]; bool bfs(int st,int ed) { memset(dep,-1,sizeof(dep)); int u; queue<int>que; que.push(st);dep[st]=0; while(!que.empty()) { u=que.front();que.pop(); for(int i=head[u];i!=-1;i=p[i].next) { if(dep[p[i].to]==-1&&p[i].w) { dep[p[i].to]=dep[u]+1; if(p[i].to==ed)return 1; que.push(p[i].to); } } } return dep[ed]!=-1; } int dfs(int st,int ed,int lim) { if(!lim||st==ed)return lim; int w=0,d; for(int i=head[st];i!=-1;i=p[i].next) { if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim)))) { p[i].w-=d; p[i^1].w+=d; w+=d; lim-=d; if(!lim)break; } } return w; } int Dinic(int st,int ed) { int sum=0; while(bfs(st,ed))sum+=dfs(st,ed,inf); return sum; } vector<int>allfa[455]; void getline(int a) { int u,v; for(u=a;u<=n;u++) { for(int i=head[u];i!=-1;i=p[i].next) { v=p[i].to; if(p[i].w!=0||i&1)continue; allfa[v].push_back(u); } } } int main() { memset(head,-1,sizeof(head)); int i,j,u,v,w,ed,res,sum=0; scanf("%d%d",&u,&v); n=u+v; ed=n+1; for(i=1;i<=u;i++) { scanf("%d",&w); sum+=w; add(i,ed,w);add(ed,i,0); } for(i=1;i<=v;i++) { scanf("%d",&w); add(0,u+i,w);add(u+i,0,0); for(j=1;j<=u;j++) { add(u+i,j,1); add(j,u+i,0); } } res=Dinic(0,ed); if(res!=sum) { printf("0 ");return 0; } printf("1 "); getline(u+1); for(i=1;i<=u;i++) { for(j=0;j<allfa[i].size();j++)printf("%d ",allfa[i][j]-u); putchar(10); } }
一件事:网络流可以在计算出当前最大流后,放松流(边)的限制再累加求扩充流量后的最大流。不影响正确性。
这道题依旧是割裂点。
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=1e6+50; struct P{ int to,w,next; }p[maxn]; int head[1050],cnt,ed,a[1050],dp[1050]; void addline(int u,int v,int w) { p[cnt].w=w; p[cnt].to=v; p[cnt].next=head[u]; head[u]=cnt++; } void add(int u,int v,int w) { addline(u,v,w); addline(v,u,0); } int dep[1050]; bool bfs(int st,int ed) { memset(dep,-1,sizeof(dep)); int u; queue<int>que; que.push(st);dep[st]=0; while(!que.empty()) { u=que.front();que.pop(); for(int i=head[u];i!=-1;i=p[i].next) { if(dep[p[i].to]==-1&&p[i].w) { dep[p[i].to]=dep[u]+1; if(p[i].to==ed)return 1; que.push(p[i].to); } } } return dep[ed]!=-1; } int dfs(int st,int ed,int lim) { if(!lim||st==ed)return lim; int w=0,d; for(int i=head[st];i!=-1;i=p[i].next) { if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim)))) { p[i].w-=d; p[i^1].w+=d; w+=d; lim-=d; if(!lim)break; } } return w; } int sum=0; int Dinic(int st,int ed) { while(bfs(st,ed))sum+=dfs(st,ed,inf); return sum; } int main() { memset(head,-1,sizeof(head)); int n,i,j,k,u,len=1; scanf("%d",&n);ed=2*n+1; for(i=1;i<=n;i++) { scanf("%d",&a[i]);dp[i]=1;add(i,i+n,1); } for(i=n-1;i>=1;i--)// dec { for(j=n;j>=i+1;j--) { if(a[i]>a[j])continue; dp[i]=max(dp[i],dp[j]+1); len=max(len,dp[i]); } for(j=n;j>=i+1;j--) { if(dp[i]==dp[j]+1&&a[i]<=a[j])add(n+i,j,1); } } printf("%d ",len); // for(i=1;i<=n;i++)printf("#%d# ",dp[i]); for(i=1;i<=n;i++) { if(dp[i]==len)add(0,i,1); if(dp[i]==1)add(n+i,ed,1); } printf("%d ",Dinic(0,ed)); if(n==1) { printf("1 "); return 0; } if(dp[1]==len)add(0,1,inf),add(1,n+1,inf); if(dp[n]==1)add(n,n*2,inf),add(n*2,ed,inf); printf("%d ",Dinic(0,ed)); }
再说一次,一件事:最小割=最大流。
即使是放在网络流,即使告诉我是最小割,我也想不到该怎么做。
暴风哭泣。┭┮﹏┭┮
推荐洛谷题解,看一遍豁然开朗一遍,下一次又重新看一遍,豁然开朗一遍。(┬_┬)
题解说,二分图,然后源点连奇点,汇点连偶点,流量为点权,中间的点,互斥的点用inf流连接。题中同奇偶性必不互斥。
#include<bits/stdc++.h> #define debug printf("!"); using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=1e4+50; struct P{ int to,w,next; }p[maxn<<3]; int head[maxn],cnt; void addline(int u,int v,int w) { p[cnt].w=w; p[cnt].to=v; p[cnt].next=head[u]; head[u]=cnt++; } void add(int u,int v,int w) { addline(u,v,w); addline(v,u,0); } int dep[maxn]; bool bfs(int st,int ed) { memset(dep,-1,sizeof(dep)); int u; queue<int>que; que.push(st);dep[st]=0; while(!que.empty()) { u=que.front();que.pop(); for(int i=head[u];i!=-1;i=p[i].next) { if(dep[p[i].to]==-1&&p[i].w) { dep[p[i].to]=dep[u]+1; if(p[i].to==ed)return 1; que.push(p[i].to); } } } return dep[ed]!=-1; } int dfs(int st,int ed,int lim) { if(!lim||st==ed)return lim; int w=0,d; for(int i=head[st];i!=-1;i=p[i].next) { if(dep[p[i].to]==dep[st]+1&&p[i].w&&(d=dfs(p[i].to,ed,min(p[i].w,lim)))) { p[i].w-=d; p[i^1].w+=d; w+=d; lim-=d; if(!lim)break; } } return w; } int Dinic(int st,int ed) { int sum=0; while(bfs(st,ed))sum+=dfs(st,ed,inf); return sum; } int main() { memset(head,-1,sizeof(head)); int n,m,st,ed,a,u,sum=0; scanf("%d%d",&n,&m); st=0;ed=n*m+1; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { scanf("%d",&a); sum+=a; u=(i-1)*m+j; if((i+j)%2) { add(st,u,a); if(j>1)add(u,u-1,inf); if(i>1)add(u,u-m,inf); if(j<m)add(u,u+1,inf); if(i<n)add(u,u+m,inf); } else add(u,ed,a); } } printf("%d ",sum-Dinic(st,ed)); }