感觉这就是一道蓝题,并不算紫题,但是这道题的思想很重要。
记得我做过的第一道网络流,用到的就是这个思想,就是拆点。
因为我们要防止中间的点被用到多次啊……
别问我为什么,因为我不会再一次解释那是因为只有边才有容量,点没有容量,一个点只要入流等于出流,无论有多少条边经过它,都是可以的。
那么我们可以把中间点拆开,再连一条边权为1的边即可。
注意:每个点的标号特备容易弄混……
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<queue> using namespace std; #define maxn 2000005 const int inf=9999999; struct node { int nxt=-1,to,w; } edge[maxn]; int dep[maxn],head[maxn]; int n,m,cnt=-1,s,t,p,q; void add(int a,int b,int c) { edge[++cnt].to=b; edge[cnt].nxt=head[a]; edge[cnt].w=c; head[a]=cnt; } int bfs() { memset(dep,0,sizeof(dep)); queue<int> q; q.push(s); dep[s]=1; while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edge[i].nxt) { int to=edge[i].to; if(!dep[to]&&edge[i].w) { dep[to]=dep[u]+1; q.push(to); } } } if(dep[t]) return 1; else return 0; } int dfs(int u,int dist) { if(u==t) return dist; int used=0,d=0; for(int i=head[u];i!=-1;i=edge[i].nxt) { if(used==dist) return dist; int to=edge[i].to; if(dep[to]==dep[u]+1&&edge[i].w) { if(d=dfs(to,min(dist-used,edge[i].w))) { edge[i].w-=d; edge[i^1].w+=d; used+=d; } } } if(!used) dep[u]=0; return used; } int dinic() { int ans=0; while(bfs()) while(int d=dfs(s,inf)) ans+=d; return ans; } int main() { memset(head,-1,sizeof(head)); scanf("%d%d%d",&n,&p,&q); s=0,t=p+2*n+q+1; for(int i=1;i<=n;i++) { for(int j=1;j<=p;j++) { int x; scanf("%d",&x); if(x) { add(j,i+p,1); add(i+p,j,0); } } } for(int i=1;i<=n;i++) for(int j=1;j<=q;j++) { int x; scanf("%d",&x); if(x) { add(p+n+i,p+2*n+j,1); add(p+2*n+j,p+n+i,0); } } for(int i=1;i<=p;i++) { add(s,i,1); add(i,s,0); } for(int i=p+1;i<=p+n;i++) { add(i,i+n,1); add(i+n,i,0); } for(int i=p+2*n+1;i<=p+2*n+q;i++) { add(i,t,1); add(t,i,0); } printf("%d",dinic()); return 0; }
原文地址:https://www.cnblogs.com/popo-black-cat/p/10293865.html
时间: 2024-11-07 19:33:16