Submit: 2925 Solved: 1221
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
网络流 最大流判定+二分+拆点
二分答案,假设可以跳lim首舞曲,那么每个人要有lim个不同的舞伴
每个人拆成三个点n1,n2,n3
从S到每个男生的n1连边,容量为lim,限制此人需要有lim个不同舞伴
从每个男生的n1到n2连边,容量为INF,表示和喜欢的人跳舞的次数没有限制
从每个男生的n1到n3连边,容量为k,表示最多和不喜欢的人跳舞的次数为k
从每个女生的n1到T连边,容量为lim;
从每个女生的n2到n1连边,容量为INF,n3到n1连边,容量为k
从每个男生向每个女生连边,如果喜欢则n2连n2,否则n3连n3,容量为1,表示只和同一个人跳一支舞
跑最大流,如果最大流等于lim*n,说明每个人都找到了lim个舞伴,可行
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 #include<queue> 9 using namespace std; 10 const int INF=1e9; 11 const int mxn=350; 12 int read(){ 13 int x=0,f=1;char ch=getchar(); 14 while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();} 15 while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} 16 return x*f; 17 } 18 struct edge{ 19 int v,nxt,f; 20 }e[mxn*mxn*20]; 21 int hd[mxn],mct=1; 22 char mp[60][60]; 23 void add_edge(int u,int v,int f){ 24 e[++mct].v=v;e[mct].nxt=hd[u];e[mct].f=f;hd[u]=mct;return; 25 } 26 void insert(int u,int v,int f){ 27 add_edge(u,v,f); 28 add_edge(v,u,0); 29 return; 30 } 31 int n,m,S,T; 32 int d[mxn]; 33 bool BFS(){ 34 memset(d,0,sizeof d); 35 queue<int>q; 36 d[S]=1; 37 q.push(S); 38 while(!q.empty()){ 39 int u=q.front();q.pop(); 40 for(int i=hd[u];i;i=e[i].nxt){ 41 int v=e[i].v; 42 if(e[i].f && !d[v]){ 43 d[v]=d[u]+1; 44 q.push(v); 45 } 46 } 47 } 48 return d[T]; 49 } 50 int DFS(int u,int lim){ 51 if(u==T)return lim; 52 int f=0,tmp; 53 for(int i=hd[u];i;i=e[i].nxt){ 54 int v=e[i].v; 55 if(d[v]==d[u]+1 && e[i].f){ 56 tmp=DFS(v,min(lim,e[i].f)); 57 e[i].f-=tmp; 58 e[i^1].f+=tmp; 59 f+=tmp; 60 lim-=tmp; 61 if(!lim)return f; 62 } 63 } 64 d[u]=0; 65 return f; 66 } 67 int Dinic(){ 68 int res=0; 69 while(BFS())res+=DFS(S,INF); 70 return res; 71 } 72 void Build(int lim){ 73 int ed=n+n; 74 int i,j; 75 for(i=1;i<=n;i++){//跳舞数量 76 insert(S,i,lim); 77 insert(i,i+ed,INF); 78 insert(i,i+ed+ed,m); 79 } 80 for(i=1;i<=n;i++){ 81 insert(i+n,T,lim); 82 insert(i+n+ed,i+n,INF); 83 insert(i+n+ed+ed,i+n,m); 84 } 85 for(i=1;i<=n;i++) 86 for(j=1;j<=n;j++){ 87 if(mp[i][j]=='Y'){ 88 insert(i+ed,j+n+ed,1); 89 } 90 else insert(i+ed+ed,j+n+ed+ed,1); 91 } 92 return; 93 } 94 void init(){ 95 memset(hd,0,sizeof hd); 96 mct=1; 97 return; 98 } 99 int ans=0; 100 void solve(){ 101 int l=1,r=500; 102 while(l<=r){ 103 int mid=(l+r)>>1; 104 init(); 105 Build(mid); 106 int res=Dinic(); 107 if(res==mid*n){ 108 ans=mid; 109 l=mid+1; 110 }else r=mid-1; 111 } 112 return; 113 } 114 int main(){ 115 int i,j; 116 n=read();m=read(); 117 S=0;T=6*n+1; 118 for(i=1;i<=n;i++) 119 scanf("%s",mp[i]+1); 120 solve(); 121 printf("%d ",ans); 122 return 0; 123 }