ZOJ-3933 Team Formation (二分图最佳完美匹配)
题目大意:n个人,分为两个阵营。现在要组成由若干支队伍,每支队伍由两个人组成并且这两个人必须来自不同的阵营。同时,每个人都有m个厌恶的对象,并且厌恶是相互的。相互厌恶的人不能组成一支队伍。问最多能组成多少支队伍,并在在队伍数最多的前提下求最多的女生数以及输出方案。
题目分析:很显然是个二分图。从阵营1的每个元素向阵营0的每个元素连一条有向边(互相厌恶的不连),这就得到一张二分图。给每条边一个权值,边两端的女生越多,权值越大。只需要求最大完美匹配即可。
ps:比赛的时候连边只连了一半儿,导致一直wa。。。
代码如下:
# include<iostream> # include<cstdio> # include<cstring> # include<vector> # include<queue> # include<list> # include<set> # include<map> # include<string> # include<cmath> # include<cstdlib> # include<algorithm> using namespace std; # define LL long long const int N=1005; const int INF=1000000000; const LL oo=0x7fffffffffffffff; const double eps=1e-10; int n; int mp[N/2+5][N/2+5]; int slack[N/2+5]; int link[N/2+5]; int lx[N/2+5]; int ly[N/2+5]; int s[N/2+5],t[N/2+5]; int vis[N/2+5][N/2+5]; string p,q; bool match(int x) { s[x]=1; for(int y=0;y<n;++y){ if(t[y]) continue; int temp=lx[x]+ly[y]-mp[x][y]; if(temp==0){ t[y]=1; if(link[y]==-1||match(link[y])){ link[y]=x; return true; } }else if(slack[y]>temp) slack[y]=temp; } return false; } void update() { int d=INF; for(int i=0;i<n;++i) if(!t[i]) d=min(d,slack[i]); for(int i=0;i<n;++i) if(s[i]) lx[i]-=d; for(int i=0;i<n;++i){ if(t[i]) ly[i]+=d; else slack[i]-=d; } } void KM() { memset(link,-1,sizeof(link)); memset(ly,0,sizeof(ly)); for(int i=0;i<n;++i){ lx[i]=-1; for(int j=0;j<n;++j) lx[i]=max(lx[i],mp[i][j]); } for(int i=0;i<n;++i){ fill(slack,slack+n,INF); while(true){ memset(s,0,sizeof(s)); memset(t,0,sizeof(t)); if(match(i)) break; update(); } } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d",&n); cin>>p>>q; memset(mp,0,sizeof(mp)); memset(vis,0,sizeof(vis)); for(int i=0;i<n;++i){ int k; scanf("%d",&k); while(k--){ int a; scanf("%d",&a); vis[i][a-1]=vis[a-1][i]=1; } for(int j=0;j<n;++j){ if(i==j||p[i]==p[j]||vis[i][j]||vis[j][i]) continue; int gg=1; ///这里如果为gg=0会wa if(q[i]=='0') ++gg; if(q[j]=='0') ++gg; if(p[i]=='1'&&p[j]=='0') mp[i][j]=gg; else if(p[i]=='0'&&p[j]=='1') mp[j][i]=gg; } } KM(); int ansa=0,ansb=0; for(int i=0;i<n;++i) if(link[i]!=-1&&mp[link[i]][i]){ ++ansa; if(q[link[i]]=='0') ++ansb; if(q[i]=='0') ++ansb; } printf("%d %d\n",ansa,ansb); for(int i=0;i<n;++i) if(link[i]!=-1&&mp[link[i]][i]) printf("%d %d\n",link[i]+1,i+1); } return 0; }