[CQOI2009]DANCE跳舞
题目描述
一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会”单向喜欢“)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
输入输出格式
输入格式:
第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为'Y'当且仅当男孩i和女孩j相互喜欢。
输出格式:
仅一个数,即舞曲数目的最大值。
输入输出样例
输入样例#1:
3 0 YYY YYY YYY
输出样例#1:
3
说明
N<=50 K<=30
题解:
很好想的最大流:
对于相互喜欢的boy and girl 我们就直接连边 容量为1
对于不喜欢的,我们要限制和不喜欢的人跳舞的人数不超过k,于是拆点,连 (i,i+n,k)
boy 和 girl 都要拆点,如果不喜欢,就将boy的辅助点和girl的辅助点相连 容量为1,就可以保证双方都<=k
然后就是二分答案,S出边和T入边权值改为mid即可
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 using namespace std; 8 const int SIZE=55,N=205,M=80005,INF=2e9; 9 int n,k;int map[SIZE][SIZE];char s[SIZE]; 10 int num=1,head[N]; 11 struct Lin{ 12 int next,to,dis; 13 }a[M]; 14 void init(int x,int y,int z){ 15 a[++num].next=head[x];a[num].to=y;a[num].dis=z;head[x]=num; 16 } 17 void addedge(int x,int y,int z){ 18 init(x,y,z);init(y,x,0); 19 } 20 int S=0,T,q[N],dep[N]; 21 bool bfs(){ 22 memset(dep,0,sizeof(dep)); 23 int t=0,sum=1,x,u; 24 q[1]=S;dep[S]=1; 25 while(t!=sum){ 26 x=q[++t]; 27 for(int i=head[x];i;i=a[i].next){ 28 u=a[i].to; 29 if(dep[u] || a[i].dis<=0)continue; 30 dep[u]=dep[x]+1;q[++sum]=u; 31 } 32 } 33 return dep[T]; 34 } 35 int dfs(int x,int flow){ 36 if(x==T || !flow)return flow; 37 int u,tot=0,tmp; 38 for(int i=head[x];i;i=a[i].next){ 39 u=a[i].to; 40 if(dep[u]!=dep[x]+1 || a[i].dis<=0)continue; 41 tmp=dfs(u,min(flow,a[i].dis)); 42 a[i].dis-=tmp;a[i^1].dis+=tmp; 43 tot+=tmp;flow-=tmp; 44 if(!flow)break; 45 } 46 if(!tot)dep[x]=0; 47 return tot; 48 } 49 int maxflow(){ 50 int tot=0,tmp; 51 while(bfs()){ 52 tmp=dfs(S,INF); 53 while(tmp)tot+=tmp,tmp=dfs(S,INF); 54 } 55 return tot; 56 } 57 void Clear(){ 58 num=1; 59 memset(head,0,sizeof(head)); 60 } 61 bool check(int lim){ 62 Clear(); 63 for(int i=1;i<=n;i++){ 64 addedge(S,i,lim);addedge(i+n+n,T,lim); 65 addedge(i,i+n,k);addedge(i+n+n+n,i+n+n,k); 66 } 67 for(int i=1;i<=n;i++) 68 for(int j=1;j<=n;j++){ 69 if(map[i][j])addedge(i,j+n+n,1); 70 else addedge(i+n,j+n+n+n,1); 71 } 72 int ret=maxflow(); 73 return ret==lim*n; 74 } 75 void work(){ 76 scanf("%d%d",&n,&k);T=4*n+1; 77 for(int i=1;i<=n;i++){ 78 scanf("%s",s); 79 for(int j=1;j<=n;j++)if(s[j-1]=='Y')map[i][j]=true; 80 } 81 int l=1,r=n,mid,ans=0; 82 while(l<=r){ 83 mid=(l+r)>>1; 84 if(check(mid))ans=mid,l=mid+1; 85 else r=mid-1; 86 } 87 printf("%d\n",ans); 88 } 89 int main() 90 { 91 work(); 92 return 0; 93 }