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
拆点+二分
把人拆成两个点 S到男孩 女孩到T连二分的答案
然后男女之间喜欢的连1 不喜欢的连1
最后把拆的点连上K
#include<bits/stdc++.h>
using namespace std;
const int inf=1e9;
int ans;
int cnt;
int head[1010],q[1010],dis[1010];
int n,k,T;
struct edge
{
int to,nxt;
int flow;
}e[500050];
inline void addedge(int x,int y,int fl)
{
e[++cnt].to=y;
e[cnt].nxt=head[x];
head[x]=cnt;
e[cnt].flow=fl;
e[++cnt].to=x;
e[cnt].nxt=head[y];
head[y]=cnt;
e[cnt].flow=0;
}
bool mp[1010][1010];
inline bool bfs()
{
int ql=0,qr=1;
q[1]=0;
memset(dis,0,sizeof(dis));
dis[0]=1;
while(ql<qr)
{
int x=q[++ql];
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(e[i].flow&&!dis[y])
{
dis[y]=dis[x]+1;
q[++qr]=y;
}
}
}
if(dis[T]) return true;
return false;
}
inline int dfs(int x,int flow)
{
if(x==T) return flow;
int d,used=0;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(e[i].flow&&dis[y]==dis[x]+1)
{
d=dfs(y,min(flow,e[i].flow));
e[i].flow-=d;
e[i^1].flow+=d;
used+=d;
if(used==flow)
return flow;
}
}
if(!used)
dis[x]=-1;
return used;
}
inline void dinic()
{
while(bfs())
ans+=dfs(0,inf);
}
inline void build(int x)
{
cnt=1;
memset(head,0,sizeof(head));
for(int i=1;i<=n;i++)
{
addedge(0,i,x);addedge(i,i+500,k);
addedge(i+n+500,i+n,k);addedge(i+n,T,x);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(mp[i][j]) addedge(i,n+j,1);
else addedge(i+500,n+j+500,1);
}
int main()
{
scanf("%d%d",&n,&k);
T=1001;
for(int i=1;i<=n;i++)
{
char ch[51];
scanf("%s",ch);
for(int j=1;j<=n;j++)
if(ch[j-1]=='Y')
mp[i][j]=1;
}
int mx=0,l=0,r=50;
while(l<=r)
{
int mid=l+r>>1;
build(mid);
ans=0;
dinic();
if(ans>=n*mid)
mx=mid,l=mid+1;
else r=mid-1;
}
cout<<mx;
}