@lpf20051024
2020-08-11T14:51:04.000000Z
字数 9166
阅读 723
网络流 题解
都是从 cnblog 来的吧,代码就贴在这里啦。
配合 原讲解+少量注释 食用更佳。
#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<cmath>#include<queue>#define N 110#define M 100100using namespace std;int n,m,head[N],match[N],cnt=0,ans=0;bool vis[N];struct Edge{int nxt,to;}ed[M];int read(){int x=0,f=1;char c=getchar();while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();while(c>='0' && c<='9') x=x*10+c-48,c=getchar();return x*f;}void add(int u,int v){ed[++cnt].nxt=head[u];ed[cnt].to=v;head[u]=cnt;return;}bool dfs(int u){for(int i=head[u];i;i=ed[i].nxt){int v=ed[i].to;if(vis[v]) continue;vis[v]=true;if(!match[v] || dfs(match[v])){match[v]=u;return true;}}return false;}int main(){n=read(),m=read()-n;int u=read(),v=read();while(u!=-1 && v!=-1){add(u,v),add(v,u);u=read(),v=read();}for(int i=1;i<=n;i++){memset(vis,false,sizeof(vis));if(dfs(i)) ++ans;}printf("%d\n",ans);for(int i=n+1;i<=n+m;i++)if(match[i]) printf("%d %d\n",match[i],i);return 0;}
#include<cstdio>#include<cstring>#include<cmath>#include<iostream>#include<algorithm>#include<queue>#define N 1010#define M 100010#define INF 0x3f3f3f3fusing namespace std;int n,m,s,t,sum=0,head[N],d[N],cnt=1;struct Edge{int nxt,to,val;}ed[M<<1];queue<int>q;int read(){int x=0,f=1;char c=getchar();while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();while(c>='0' && c<='9') x=x*10+c-48,c=getchar();return x*f;}void add(int u,int v,int w){ed[++cnt].nxt=head[u];ed[cnt].to=v;ed[cnt].val=w;head[u]=cnt;ed[++cnt].nxt=head[v];ed[cnt].to=u;ed[cnt].val=0;head[v]=cnt;}bool bfs(){memset(d,0,sizeof(d));while(!q.empty()) q.pop();d[s]=1;q.push(s);while(!q.empty()){int u=q.front();q.pop();for(int i=head[u];i;i=ed[i].nxt){int v=ed[i].to,w=ed[i].val;if(w && !d[v]){d[v]=d[u]+1;if(v==t) return true;q.push(v);}}}return false;}int dinic(int u,int flow){if(u==t) return flow;int rest=flow;for(int i=head[u];i && rest;i=ed[i].nxt){int v=ed[i].to,w=ed[i].val;if(w && d[v]==d[u]+1){int k=dinic(v,min(rest,w));if(!k) d[v]=0;ed[i].val-=k;ed[i^1].val+=k;rest-=k;}}return flow-rest;}int main(){n=read(),m=read();s=0,t=n+m+1;for(int i=1;i<=n;i++){int a=read();sum+=a;//记录代表总数。add(s,i,a);}for(int i=1;i<=m;i++){int a=read();add(i+n,t,a);}for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)add(i,j+n,1);int ans=0,flow;while(bfs())if(flow=dinic(s,INF)) ans+=flow;if(ans<sum){puts("0");return 0;}puts("1");for(int u=1;u<=n;u++){for(int i=head[u];i;i=ed[i].nxt){int v=ed[i].to,w=ed[i].val;if(v!=s && !w) printf("%d ",v-n);//根据残量网络输出。}puts("");}return 0;}
#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#include<iostream>#include<queue>#define N 510#define M 100010#define INF 0x3f3f3f3fusing namespace std;int n,m,s,t,head[N],fa[N],d[N],cnt=1;struct Edge{int nxt,frm,to,val;}ed[M];queue<int>q;int read(){int x=0,f=1;char c=getchar();while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();while(c>='0' && c<='9') x=x*10+c-48,c=getchar();return x*f;}void add(int u,int v,int w){ed[++cnt]=(Edge){head[u],u,v,w};head[u]=cnt;ed[++cnt]=(Edge){head[v],v,u,0};head[v]=cnt;}void build(){//建图。n=read(),m=read();s=0,t=n<<1|1;for(int i=1;i<=m;i++){int u=read(),v=read();add(u,v+n,1);}for(int i=1;i<=n;i++) add(s,i,1);for(int i=1;i<=n;i++) add(i+n,t,1);return;}bool bfs(){while(!q.empty()) q.pop();memset(d,0,sizeof(d));d[s]=1;q.push(s);while(!q.empty()){int u=q.front();q.pop();for(int i=head[u];i;i=ed[i].nxt){int v=ed[i].to,w=ed[i].val;if(w && !d[v]){d[v]=d[u]+1;if(v==t) return true;q.push(v);}}}return false;}int Dinic(int u,int flow){if(u==t) return flow;int rest=flow;for(int i=head[u];i && rest;i=ed[i].nxt){int v=ed[i].to,w=ed[i].val;if(w && d[v]==d[u]+1){int k=Dinic(v,min(rest,w));if(!k) d[v]=0;ed[i].val-=k;ed[i^1].val+=k;rest-=k;}}return flow-rest;}int find(int x){if(fa[x]==x) return x;return fa[x]=find(fa[x]);}void Print(int u){printf("%d ",u);for(int i=head[u];i;i=ed[i].nxt)if(!ed[i].val && ed[i].to>n)Print(ed[i].to-n);//递归输出。return;}void work(){int flow,ans=0;while(bfs())if(flow=Dinic(s,INF)) ans+=flow;for(int i=1;i<=n;i++) fa[i]=i;for(int i=2;i<=cnt;i++){int u=ed[i].frm,v=ed[i].to,w=ed[i].val;if(u>s && u<=n && v>n && v<t && !w)//找到被匹配了的边,表示这两点被合并了。fa[find(v-n)]=find(u);//与一般并查集不同的是 v-n 和 u 的顺序不可调换。//因为 u 在路径上的位置必然在 v-n 之前,而路径的输出需要考虑递归的顺序。}for(int i=1;i<=n;i++)if(fa[i]==i) Print(i),puts("");printf("%d\n",n-ans);return;}int main(){build();work();return 0;}
//真就是一道挺板子的题目啊。#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<queue>#define N 10010#define M 200010#define INF 0x3f3f3f3fusing namespace std;int m,n,s,t,head[N],d[N],cnt=1;struct Edge{int nxt,to,val;}ed[M];queue<int>q;int read(){int x=0,f=1;char c=getchar();while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();while(c>='0' && c<='9') x=x*10+c-48,c=getchar();return x*f;}void add(int u,int v,int w){ed[++cnt]=(Edge){head[u],v,w};head[u]=cnt;ed[++cnt]=(Edge){head[v],u,0};head[v]=cnt;return;}bool bfs(){while(!q.empty()) q.pop();memset(d,0,sizeof(d));d[s]=1;q.push(s);while(!q.empty()){int u=q.front();q.pop();for(int i=head[u];i;i=ed[i].nxt){int v=ed[i].to,w=ed[i].val;if(w && !d[v]){d[v]=d[u]+1;if(v==t) return true;q.push(v);}}}return false;}int Dinic(int u,int flow){if(u==t) return flow;int rest=flow;for(int i=head[u];i && rest;i=ed[i].nxt){int v=ed[i].to,w=ed[i].val;if(w && d[v]==d[u]+1){int k=Dinic(v,min(rest,w));if(!k) d[v]=0;ed[i].val-=k;ed[i^1].val+=k;rest-=k;}}return flow-rest;}int main(){n=read(),m=read();int a,b,sum=0;s=0,t=n+m+1;for(int i=1;i<=n;i++)a=read(),sum+=a,add(s,i,a);for(int i=1;i<=m;i++){a=read();while(a--) b=read(),add(b,i+n,1);}for(int i=1;i<=m;i++)add(i+n,t,1);int ans=0,flow;while(bfs())if(flow=Dinic(s,INF)) ans+=flow;if(ans<sum){puts("No Solution!");return 0;}for(int u=1;u<=n;u++){printf("%d: ",u);for(int i=head[u];i;i=ed[i].nxt)if(!ed[i].val && ed[i].to>n) printf("%d ",ed[i].to-n);puts("");}return 0;}
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<queue>#include<cmath>#define N 1000010#define M 2000010#define s 0#define t 1000000#define INF 0x3f3f3f3fusing namespace std;int n,head[N],frs[N],pre[N],d[N],cnt=1;bool vis[N];struct Edge{int nxt,to,val;}ed[M];queue<int>q;int read(){int x=0,f=1;char c=getchar();while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();while(c>='0' && c<='9') x=x*10+c-48,c=getchar();return x*f;}void add(int u,int v,int w){ed[++cnt]=(Edge){head[u],v,w};head[u]=cnt;ed[++cnt]=(Edge){head[v],u,0};head[v]=cnt;return;}bool bfs(){while(!q.empty()) q.pop();memset(d,0,sizeof(d));d[s]=1;q.push(s);while(!q.empty()){int u=q.front();q.pop();for(int i=head[u];i;i=ed[i].nxt){int v=ed[i].to,w=ed[i].val;if(w && !d[v]){d[v]=d[u]+1;if(v==t) return true;q.push(v);}}}return false;}int Dinic(int u,int flow){if(u==t) return flow;int rest=flow;for(int i=head[u];i && rest;i=ed[i].nxt){int v=ed[i].to,w=ed[i].val;if(w && d[v]==d[u]+1){int k=Dinic(v,min(w,rest));if(!k) d[v]=0;ed[i].val-=k;ed[i^1].val+=k;rest-=k;pre[u>>1]=v>>1;//开始建图时乘 2 了。//很巧的是 (u<<1)>>1=(u<<1|1)>>1=u。}}return flow-rest;}int main(){n=read();int now=0,Pillar=0;while(Pillar<=n){//如果柱子数 > n 就退出。++now;add(s,now<<1,1);//和源点连接。add(now<<1|1,t,1);//和汇点连接。for(int i=sqrt(now)+1;i*i<(now<<1);i++)//和比自己小的能与自己组成完全平方数的数连边。add((i*i-now)<<1,now<<1|1,1);//注意细节。int flow,ans=0;while(bfs())if(flow=Dinic(s,INF)) ans+=flow;if(!ans)//如果找不到增广路。frs[++Pillar]=now;}printf("%d\n",--now);//记得减 1,因为最后的球肯定是放在第 n+1 个柱子上的。memset(vis,false,sizeof(vis));for(int i=1;i<=n;i++){if(vis[frs[i]]) continue;//如果之前见过你了就不用输出了。for(int u=frs[i];u && u!=(t>>1);u=pre[u])vis[u]=true,printf("%d ",u);puts("");}return 0;}
#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<algorithm>#include<cstdlib>#define N 1000010#define M 2000010#define P 110#define s 0#define t N-10#define INF 0x3f3f3f3fusing namespace std;int n,m,k,ans,head[N],cnt=1;int d[N];int r[P],g[P][P],h[P];int fa[P],q[N];struct Edge{int nxt,to,val;}ed[M];int read(){int x=0,f=1;char c=getchar();while(c<'0' || c>'9') f=(c=='-')?-1:1,c=getchar();while(c>='0' && c<='9') x=x*10+c-48,c=getchar();return x*f;}void init(){n=read(),m=read(),k=read();for(int i=1;i<=m;i++){h[i]=read(),r[i]=read();for(int j=0;j<r[i];j++) g[i][j]=read();}return;}int find(int x){if(fa[x]==x) return x;return fa[x]=find(fa[x]);}void merge(int x,int y){int fx=find(x);int fy=find(y);if(fx!=fy) fa[fx]=fy;return;}void pre_chck(){for(int i=1;i<=n+2;i++) fa[i]=i;for(int i=1;i<=m;i++)for(int j=0;j<r[i];j++){if(g[i][j]==0) g[i][j]=n+1;if(g[i][j]==-1) g[i][j]=n+2;if(j!=0) merge(g[i][j],g[i][j-1]);}if(find(n+1)!=find(n+2)){puts("0");exit(0);}return;}void add(int u,int v,int w){ed[++cnt]=(Edge){head[u],v,w};head[u]=cnt;ed[++cnt]=(Edge){head[v],u,0};head[v]=cnt;return;}bool bfs(){for(int i=1;i<=ans*(n+1);i++) d[i]=0;//千万别用 memset。d[t]=0;d[s]=1;q[1]=s;int h=1,tail=1;while(h<=tail){int u=q[h];++h;for(int i=head[u];i;i=ed[i].nxt){int v=ed[i].to,w=ed[i].val;if(w && !d[v]){d[v]=d[u]+1;if(v==t) return true;q[++tail]=v;}}}return false;}int Dinic(int u,int flow){if(u==t) return flow;int i,rest=0;for(i=head[u];i;i=ed[i].nxt){int v=ed[i].to,w=ed[i].val;if(w && d[v]==d[u]+1){int k=Dinic(v,min(flow-rest,w));if(!k) d[v]=0;ed[i].val-=k;ed[i^1].val+=k;rest+=k;if(rest==flow) return rest;}}return rest;}int main(){init();pre_chck();//并查集判无解。int now=0;for(ans=1;;ans++){add(s,ans*(n+1),INF);for(int i=1;i<=m;i++){int x=(ans-1)%r[i],y=ans%r[i];if(g[i][x]==n+2) x=t;else x=(ans-1)*(n+1)+g[i][x];if(g[i][y]==n+2) y=t;else y=ans*(n+1)+g[i][y];add(x,y,h[i]);}//日常建边。while(bfs()) now+=Dinic(s,INF);//利用残量网络跑 Dinic。if(now>=k){printf("%d\n",ans);return 0;}for(int i=1;i<=n+1;i++)add((ans-1)*(n+1)+i,ans*(n+1)+i,INF);//向下一层转移。}return 0;}