BZOJ1305 [CQOI2009]dance跳舞 最大流+二分

一次舞会有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..


发布了39 篇原创文章 · 获赞 4 · 访问量 5817

猜你喜欢

转载自blog.csdn.net/Wolf_Reiser/article/details/78587179
今日推荐