说一下建图过程, 虚拟源点 s, 汇点 t 。对于猜想本来是0的人i,建边(s,i,1) ,猜想为1的 建边(i, t, 1) 。对于是一对朋友的 ,建边(i,j,1) ,(j,i,1) 。由最小割的性质=最大流。故用dinic求一次最大流即可。
VIEW CODE
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<queue> #include<stack> #include<string> #include<cstring> #include<map> #include<vector> #include<set> #include<ctime> #include<stdlib.h> using namespace std; const int mmax= 310; const int mod=1000000007; const int inf=0x3fffffff; using namespace std; struct node { int flow; int en; int next; }E[2*mmax*mmax]; int p[mmax]; int num; void init() { memset(p,-1,sizeof p); num=0; } void add(int st,int en,int flow) { E[num].en=en; E[num].flow=flow; E[num].next=p[st]; p[st]=num++; E[num].en=st; E[num].flow=0; E[num].next=p[en]; p[en]=num++; } int d[mmax]; bool vis[mmax]; int qq[mmax]; int cur[mmax]; bool bfs(int st,int en) { memset(vis,0,sizeof vis); int qcnt=0; qq[++qcnt]=st; d[st]=0; vis[st]=1; while(qcnt) { int x=qq[qcnt]; qcnt--; for(int i=p[x]; i+1; i=E[i].next) { int v=E[i].en; if(!vis[v]&&E[i].flow) { vis[v]=1; qq[++qcnt]=v; d[v]=d[x]+1; } } } return vis[en]; } int dfs(int st,int en,int flow) { if(st==en||flow==0) return flow; int f=0,dd; for(int &i=cur[st]; i+1;i=E[i].next) { int v=E[i].en; if(d[st]+1==d[v]&&(dd=dfs(v,en,min(flow,E[i].flow)))>0) { E[i].flow-=dd; E[i^1].flow+=dd; flow-=dd; f+=dd; if(flow==0) break; } } return f; } int dinic(int st,int en,int n) { int flow=0; while(bfs(st,en)) { for(int i=0;i<=n;i++) cur[i]=p[i]; flow+=dfs(st,en,inf); } return flow; } int main() { int n,m; while(cin>>n>>m && n+m) { init(); int d; for(int i=1;i<=n;i++) { scanf("%d",&d); if(!d) add(0,i,1); else add(i,n+1,1); } for(int i=0;i<m;i++) { int u,v; scanf("%d %d",&u,&v); add(u,v,1); add(v,u,1); } printf("%d\n",dinic(0,n+1,n+1)); } return 0; }
原文地址:http://blog.csdn.net/u012127882/article/details/43486397