1305: [CQOI2009]dance跳舞
Time Limit: 5 Sec Memory Limit: 162 MBDescription
一次舞会有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
垃圾网络流1A,增加超级源汇+分裂点+最大流+二分。
男,女各分裂成喜欢yes和不喜欢no两个点
若男女是cp,则每个男yes-->每个女yes 容量1
若男女不是cp,则每个男no-->每个女no 容量1
控制:每个男孩都不会和同一个女孩跳两首(或更多)舞曲。
每个男yes-->自己no 容量k
每个女no-->自己yes 容量k
控制:每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。
最后二分x(暴力枚举ok,数据弱爆了!)
S--->每个男yes 容量x
每个女yes--->T 容量x
若最大流==x*人数(即满流) 则成立。
控制:每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。
ISAP!!!跑的飞快。。。
#include<iostream>
#include<fstream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<vector>
#include<queue>
#include<deque>
#include<utility>
#include<map>
#include<set>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<functional>
#include<sstream>
#include<cstring>
#include<bitset>
#include<stack>
using namespace std;
int n,m,s,t,cnt,x,y,z,k,ans;
char ss[55][55];
struct sdt
{
int cap,flow,u,v;
}e[200005];
int nxt[200005],fir[10005],d[10005],par[10005],num[10005],cur[10005];
bool vis[10005];
int read()
{
int x=0;char c=getchar();
while(c<48||c>57)c=getchar();
while(c>47&&c<58)x*=10,x+=c-48,c=getchar();
return x;
}
void add(int u,int v,int cp,int fl)
{
e[++cnt].u=u;e[cnt].v=v;e[cnt].cap=cp;e[cnt].flow=fl;
nxt[cnt]=fir[u];fir[u]=cnt;
}
void bfs()
{
memset(vis,0,sizeof(vis));
memset(d,0,sizeof(d));
queue<int>q;
d[t]=0;
vis[t]=1;
q.push(t);
while(!q.empty())
{
int k=q.front();
q.pop();
for(int i=fir[k];i;i=nxt[i])
{
if(!vis[e[i].v] && e[i].cap==0)
{
vis[e[i].v]=1;
d[e[i].v]=d[k]+1;
q.push(e[i].v);
}
}
}
}
int agument()
{
int p=t;
int ans=2147483647;
while(p!=s)
{
ans=min(ans,e[par[p]].cap-e[par[p]].flow);
p=e[par[p]].u;
}
p=t;
while(p!=s)
{
e[par[p]].flow+=ans;
e[par[p]^1].flow-=ans;
p=e[par[p]].u;
}
return ans;
}
int isap()
{
memset(num,0,sizeof(num));
int flow=0;
for(int i=1;i<=n;i++)
{
num[d[i]]++;
cur[i]=fir[i];
}
int p=s;
while(d[s]<n)
{
if(p==t)
{
flow+=agument();
p=s;
}
bool ok=0;
for(int i=cur[p];i;i=nxt[i])
{
if(e[i].cap>e[i].flow && d[p]==d[e[i].v]+1)
{
ok=1;
par[e[i].v]=i;
cur[p]=i;
p=e[i].v;
break;
}
}
if(!ok)
{
int mn=n-1;
for(int i=fir[p];i;i=nxt[i])
{
if(e[i].cap>e[i].flow)mn=min(mn,d[e[i].v]);
}
if(--num[d[p]]==0)break;
num[d[p]=mn+1]++;
cur[p]=fir[p];
if(p!=s)p=e[par[p]].u;
}
}
return flow;
}
void build(int yhy)
{
memset(nxt,0,sizeof(nxt));
memset(fir,0,sizeof(fir));
cnt=1;
for(int i=1;i<=m;i++)
{
add(1,1+i,yhy,0);
add(1+i,1,0,0);
add(1+2*m+i,t,yhy,0);
add(t,1+2*m+i,0,0);
for(int j=0;j<m;j++)
{
if(ss[i][j]=='Y')
{
add(1+i,1+2*m+j+1,1,0);
add(1+2*m+j+1,i+1,0,0);
}
else
{
add(1+m+i,1+3*m+j+1,1,0);
add(1+3*m+j+1,1+i+m,0,0);
}
}
add(1+i,1+m+i,k,0);
add(1+m+i,1+i,0,0);
add(1+3*m+i,1+2*m+i,k,0);
add(1+2*m+i,1+3*m+i,0,0);
}
}
int main()
{
m=read();
k=read();
n=2+4*m;
s=1;
t=2+4*m;
for(int i=1;i<=m;i++)
{
for(int j=0;j<m;j++)
{
cin>>ss[i][j];
}
}
int l=0,r=m;
while(l<=r)
{
int mid=(l+r)/2;
build(mid);
bfs();
if(isap()==mid*m)
{
l=mid+1;
ans=mid;
}
else
{
r=mid-1;
}
}
printf("%d\n",ans);
return 0;
}