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 · 訪問量 9464
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章