[BZOJ1305][CQOI2009]跳舞(网络流)
1305: [CQOI2009]dance跳舞
Time Limit: 5 Sec Memory Limit: 162 MB
Submit: 3944 Solved: 1692
[Submit][Status][Discuss]Description
一 次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相 互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男 孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
Input
第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为'Y'当且仅当男孩i和女孩j相互喜欢。
Output
仅一个数,即舞曲数目的最大值。
Sample Input
3 0
YYY
YYY
YYY
Sample Output
3HINT
N<=50 K<=30
Source
[Submit][Status][Discuss]
显然是一个二分图匹配的问题,将每个人拆成两个点:喜欢点i和讨厌点i',每个限制依次考虑:
1.一对只跳一次:喜欢则i和j连1的边,讨厌则i'和j'连1的边。
2.讨厌至多k个:i向i'连k的边,j'向j连k的边。
3.但是这样直接跑之后并不能得到结果,因为不保证同性之间没有冲突,所以必须二分答案mid,S向i连mid边,j向T连mid边。
跑$O(\log n)$次最大流即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rep(i,l,r) for (int i=l; i<=r; i++) 5 #define For(i,x) for (int i=h[x],k; i; i=nxt[i]) 6 using namespace std; 7 8 const int N=1010,M=500100,inf=0x3f3f3f3f; 9 char ch; 10 int n,k,cnt,ans,mx,mid,S,T,d[N],q[M],h[N],f[M],nxt[M],to[M],mp[N][N]; 11 12 void add(int u,int v,int w){ 13 to[++cnt]=v; f[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; 14 to[++cnt]=u; f[cnt]=0; nxt[cnt]=h[v]; h[v]=cnt; 15 } 16 17 int bfs(){ 18 rep(i,0,T) d[i]=0; d[S]=1; q[1]=S; 19 for (int st=0,ed=1; st!=ed; ){ 20 int x=q[++st]; 21 For(i,x) if (!d[k=to[i]] && f[i]) q[++ed]=k,d[k]=d[x]+1; 22 } 23 return d[T]; 24 } 25 26 int dfs(int x,int lim){ 27 if (x==T) return lim; 28 int c=0,t; 29 For(i,x) if (d[k=to[i]]==d[x]+1 && f[i]){ 30 t=dfs(k,min(lim-c,f[i])); 31 f[i]-=t; f[i^1]+=t; c+=t; 32 if (c==lim) return lim; 33 } 34 if (!c) d[x]=-1; 35 return c; 36 } 37 38 void build(){ 39 cnt=1; memset(h,0,sizeof(h)); 40 S=4*n+1,T=4*n+2; 41 rep(i,1,n) add(S,i,mid),add(i,i+n,k),add(i+2*n,i+3*n,k),add(i+3*n,T,mid); 42 rep(i,1,n) rep(j,1,n) if (mp[i][j]) add(i,j+3*n,1); else add(i+n,j+2*n,1); 43 } 44 45 int main(){ 46 freopen("bzoj1305.in","r",stdin); 47 freopen("bzoj1305.out","w",stdout); 48 scanf("%d%d",&n,&k); 49 rep(i,1,n) rep(j,1,n) scanf(" %c",&ch),mp[i][j]=(ch=='Y'); 50 int L=0,R=n; 51 while (L<=R){ 52 mid=(L+R)>>1; build(); 53 ans=0; while (bfs()) ans+=dfs(S,inf); 54 if (ans>=n*mid) mx=mid,L=mid+1; else R=mid-1; 55 } 56 printf("%d\n",mx); 57 return 0; 58 }