题目链接:http://acm.hust.edu.cn/problem.php?id=1024
题目大意:舞会上,男孩和女孩配对,求最大完全匹配个数,要求每个人最多与k个不喜欢的人配对,且每次都和不同的人配对。
题目思路:网络流+拆点
这题可以看成求最多次能做几次二分图完全匹配,即最大流刚好为点的倍数,于是可以二分答案,然后用最大流判断是否可行,关键在于构图:
二分答案ans;
将每个男孩看成左边的点X,女孩为右边的点Y,然后将X分为与自己喜欢的跳舞Xa,不喜欢的Xb,Y同分为Ya,Yb,在源点src与所以Xa之间连一条容量为ans的有向边,在Ya与汇点dest之间连一条容量为ans的有向边,在Xa与Xb,Yb与Ya之间连一条有向边,之后在枚举所以男孩i,女孩j,如果i可以和j一起,则在Xai与Yaj之间连一条容量为1的有向边,否则在Xbi与Ybj之间连一条有向边,当前最大流如果为n*ans可行。。。(摘自网上)
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<string> #include<queue> #include<algorithm> #include<vector> #include<stack> #include<list> #include<iostream> #include<map> using namespace std; #define inf 0x7f3f3f3f #define Max 500 int max(int a,int b) { return a>b?a:b; } int min(int a,int b) { return a<b?a:b; } int dis[Max],gap[Max],pre[Max],cur[Max],p[Max]; //int d[4][2]={0,1,1,0,0,-1,-1,0}; int mp[220][220]; int n,m,s,t,eid; struct node { int to,next,c; }e[4*Max*Max],ee[4*Max*Max]; void addedge(int u,int v,int c) { ee[eid].to=v; ee[eid].c=c; ee[eid].next=p[u]; p[u]=eid++; } int ISAP(int st,int ed,int n,int count) ///起点,终点,顶点数 { memset(dis, 0, sizeof(dis)); memset(gap, 0, sizeof(gap)); gap[0]=n; memcpy(cur, p, sizeof(p)); ///memcpy! int i,flag,v,u=pre[st]=st,maxflow=0,aug=inf; //puts("akk"); while(dis[st] < n) { for(flag=0,i=cur[u];i!=-1; i=e[i].next) /// cur[u] if(e[i].c&& dis[u] == dis[e[i].to]+1) { flag = 1; break; } if(flag) { if(aug > e[i].c) aug = e[i].c; v = e[i].to; pre[v] = u; cur[u] = i; u = v; if(u == ed) { for(u=pre[u]; 1;u=pre[u]) ///notice! { e[cur[u]].c -= aug; e[cur[u]^1].c += aug; if(u==st) break; // puts("akkk"); } maxflow += aug; aug = inf; } } else { int minx = n; for(i=p[u]; i!=-1; i=e[i].next) if(e[i].c&& dis[e[i].to]<minx) { minx = dis[e[i].to]; cur[u] = i; } if(--gap[dis[u]] == 0) break; dis[u] = minx+1; gap[dis[u]]++; u = pre[u]; } } // printf("Case %d:\n%d\n",count,maxflow); // printf("%d\n",maxflow); return maxflow; } int main() { int m,n,t,count=1; int u,v,c,i,j,k,x,y; scanf("%d",&t); while(t--) { scanf("%d%d%d",&n,&m,&k); memset(mp,0,sizeof(mp)); memset(p,-1,sizeof(p)); eid=0; while(m--) { scanf("%d%d",&u,&v); mp[u][v]=1; addedge(u,v+n,1); addedge(v+n,u,0); } for(i=1;i<=n;i++) { addedge(i,i+2*n,k); addedge(i+2*n,i,0); addedge(i+3*n,i+n,k); addedge(i+n,i+3*n,0); addedge(0,i,0); addedge(i,0,0); addedge(i+n,4*n+1,0); addedge(4*n+1,i+n,0); for(j=1;j<=n;j++) { if(!mp[i][j]) { addedge(i+2*n,j+3*n,1); addedge(j+3*n,i+2*n,0); } } } int l,r,mid; l=1;r=n; // printf("%d\n",eid); puts("akkkk"); while(l<=r) { mid=(l+r)>>1; for(i=0;i<=eid;i++) { e[i]=ee[i]; } for(i=p[0];i!=-1;i=e[i].next) { e[i].c=mid; e[i^1].c=0; } for(i=p[4*n+1];i!=-1;i=e[i].next) { e[i].c=0; e[i^1].c=mid; } if(ISAP(0,4*n+1,4*n+2,count++)==mid*n) l=mid+1; else r=mid-1; } // ISAP(0,n*m+1,n*m+2,count++); printf("%d\n",r); } }