一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?n<=50.
看到数据范围可以考虑网络流建模.
把每个男孩和女孩拆成两个点,分别表示喜欢和不喜欢.
设每次二分的答案是x.
源点向每个男孩的喜欢点连一条x的边,每个女孩的喜欢点向汇点连一条x的边
考虑每一对是否喜欢
如果喜欢就在两人喜欢点之间连1的边,
反之在不喜欢点之间连1的边。
最后在从男孩的喜欢向不喜欢,女孩的不喜欢向喜欢连K的边.
这样就解决了所有题中的限制条件,跑最大流即可.
#include<bits/stdc++.h>
#define LL long long
#define clr(x,i) memset(x,i,sizeof(x))
using namespace std;
const int N=202,INF=9999999;
struct Edge{
int to,nex,cap;
}edge[N*N*2];
int n,K,tot,head[N],cur[N];
inline void Add(int u,int v,int c)
{
edge[++tot].to=v;edge[tot].nex=head[u];edge[tot].cap=c;head[u]=tot;
edge[++tot].to=u;edge[tot].nex=head[v];edge[tot].cap=0;head[v]=tot;
}
char str[N][N];
int s,t,que[N*N*4],dist[N*4];
bool bfs()
{
clr(dist,60);
dist[s]=0;que[1]=s;
int l=0,r=1;
while(l<r)
{
int u=que[++l];
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].to,cap=edge[i].cap;
if(dist[v]>INF&&cap>0)
dist[v]=dist[u]+1,que[++r]=v;
}
}
return dist[t]<INF;
}
int dfs(int u,int maxf)
{
if(u==t)return maxf;
for(int i=cur[u];i;i=edge[i].nex){
cur[u]=i;//当前弧
int v=edge[i].to,cap=edge[i].cap;
if(dist[v]==dist[u]+1&&cap>0){
int flow=dfs(v,min(maxf,cap));
if(flow){
edge[i].cap-=flow;
edge[i^1].cap+=flow;
return flow;
}
}
}
return 0;///这个经常忘...
}
int dinic()
{
int ret=0,flow;
while(bfs()){
for(int i=s;i<=t;i++)cur[i]=head[i];
while(flow=dfs(s,INF))
ret+=flow;
}
return ret;
}
void work(int now)
{
tot=1;clr(head,0);
s=0;t=n*4+1;
for(int i=1;i<=n;i++){
Add(s,i,now);Add(i,n+i,K);
Add(n*2+i,t,now);Add(n*3+i,n*2+i,K);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(str[i][j]=='Y')
Add(i,n*2+j,1);
else
Add(n+i,n*3+j,1);
}
int main()
{
//freopen("bzoj1305.in","r",stdin);
scanf("%d%d",&n,&K);
for(int i=1;i<=n;i++)
scanf("%s",str[i]+1);
int l=0,r=n,mid,ans=0;
while(l<=r){
mid=(l+r)>>1;
work(mid);
if(dinic()>=mid*n)
l=mid+1,ans=mid;
else
r=mid-1;
}
printf("%d",ans);
return 0;
}
这个当前弧优化真的是神级优化...
本地跑出来也是将近100倍的差距...
orz..