1305: [CQOI2009]dance跳舞
Submit: 4169 Solved: 1804
[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
YYY
YYY
YYY
Sample Output
3
HINT
N<=50 K<=30
Source
加强数据By dwellings and liyizhen2
乍一看以为多重二分图匹配,花了半个小时写出来82分WA了,搜一遍题解才知道是网络流最大流拆点
将所有人拆为两个点,男生为xi,xj,女生为yi,yj
将相互喜欢的人,由xi连向yi,容量为1
将互相不喜欢的人,由xj连向yj,容量为1
将所有男生的xi连向xj,容量为k
将所有女生yj连向yi,容量为k
将源点连向xi,容量为a
yi连向汇点,容量为a
二分法枚举容量a,计算最大流,若flow<n*a,即无法满流,则停止二分
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 7 const int INF=0x7f7f7f7f; 8 const int MAXN=400000; 9 10 struct Edge 11 { 12 int to,w,next; 13 }E[MAXN]; 14 int node=1,head[MAXN],dis[MAXN]; 15 int s=0,t=1000; 16 int n,k,ans; 17 bool mp[100][100]; 18 19 void insert(int u,int v,int w) 20 { 21 E[++node]=(Edge){v,w,head[u]}; 22 head[u]=node; 23 E[++node]=(Edge){u,0,head[v]}; 24 head[v]=node; 25 } 26 27 bool bfs() 28 { 29 memset(dis,-1,sizeof(dis)); 30 queue<int> Q; 31 Q.push(s); 32 dis[s]=0; 33 while(!Q.empty()) 34 { 35 int q=Q.front();Q.pop(); 36 for(int i=head[q];i;i=E[i].next) 37 if(E[i].w&&dis[E[i].to]==-1) 38 { 39 Q.push(E[i].to); 40 dis[E[i].to]=dis[q]+1; 41 } 42 } 43 return dis[t]!=-1; 44 } 45 46 int dfs(int x,int flow) 47 { 48 if(x==t) return flow; 49 int w,used=0; 50 for(int i=head[x];i;i=E[i].next) 51 if(E[i].w&&dis[E[i].to]==dis[x]+1) 52 { 53 w=flow-used; 54 w=dfs(E[i].to,min(w,E[i].w)); 55 E[i].w-=w; 56 E[i^1].w+=w; 57 used+=w; 58 if(used==flow)return flow; 59 } 60 if(!used) dis[x]=-1; 61 return used; 62 } 63 64 void dinic() 65 { 66 while(bfs()) ans+=dfs(s,INF); 67 } 68 69 int main() 70 { 71 scanf("%d%d",&n,&k); 72 for(int i=1;i<=n;i++) 73 { 74 char ch[100]; 75 scanf("%s",ch); 76 for(int j=1;j<=n;j++) 77 if(ch[j-1]=='Y') mp[i][j]=1; 78 } 79 int left=0,right=50; 80 while(left<=right) 81 { 82 int mid=(left+right)>>1; 83 node=1;memset(head,0,sizeof(head)); 84 for(int i=1;i<=n;i++) 85 { 86 insert(0,i,mid); 87 insert(i,i+500,k); 88 insert(n+i+500,n+i,k); 89 insert(n+i,t,mid); 90 for(int j=1;j<=n;j++) 91 if(mp[i][j]) insert(i,j+n,1); 92 else insert(i+500,j+n+500,1); 93 } 94 ans=0;dinic(); 95 if(ans>=n*mid) left=mid+1; 96 else right=mid-1; 97 } 98 printf("%d",left-1); 99 return 0; 100 }