【题解】P3153 [CQOI2009]跳舞

原题链接

[CQOI2009]跳舞

题目描述

一次舞会有 n 个男孩和 n 个女孩。

每首曲子开始时,所有男孩和女孩恰好配成 n 对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。

有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和 k 个不喜欢的女孩跳舞,而每个女孩也最多只愿意和 k 个不喜欢的男孩跳舞。

给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?

输入格式

第一行包含两个整数 nk

以下 n 行每行包含 n 个字符,每个字符只可能是 YN。第 (i+1) 行的第 j 个字符为 Y 当且仅当男孩 i 和女孩 j 相互喜欢。

输出格式

一行一个整数代表舞曲数目的最大值。

样例 #1

样例输入 #1

3 0
YYY
YYY
YYY

样例输出 #1

3

提示

数据规模与约定

  • 对于 100% 的数据,保证 1n501k30

题解

答案明显满足单调性,于是直接每次重新构造网络,随便跑网络流。
网络流比较重要的一点:建图要包含所有信息

#include<bits/stdc++.h>
using namespace std;
inline int rd(){
	int f=1,j=0;
	char w=getchar();
	while(!isdigit(w)){
		if(w=='-')f=-1;
		w=getchar();
	}
	while(isdigit(w)){
		j=j*10+w-'0';
		w=getchar();
	}
	return f*j;
}

const int N=1001,M=100001;
int head[N],to[M],fro[M],flo[M],tail=1;
int n,m,dep[N];
char S[N];
bool like[51][51],walk[N];
int s,t,cnt,poi[101][2];

inline void adlin(int x,int y,int z){
	to[++tail]=y;
	fro[tail]=head[x];
	head[x]=tail;
	flo[tail]=z;
	to[++tail]=x;
	fro[tail]=head[y];
	head[y]=tail;
	flo[tail]=0;
	return ;
}
bool bfs(){
	for(int i=1;i<=cnt;i++)dep[i]=walk[i]=0;
	dep[s]=1;
	deque<int>lin;
	lin.push_back(s),walk[s]=true;
	while(!lin.empty()){
		int u=lin.front();lin.pop_front();
		for(int k=head[u];k;k=fro[k]){
			int x=to[k];
			if(!flo[k]||walk[x])continue;
			walk[x]=true,dep[x]=dep[u]+1;
			lin.push_back(x);
		}
	}
	return walk[t];
}
int dfs(int u,int last){
	if(!last||u==t)return last;
	int had=0;
	for(int k=head[u];k;k=fro[k]){
		int x=to[k],y;
		if(!flo[k]||dep[x]<=dep[u]||!(y=dfs(x,min(last,flo[k]))))continue;
		had+=y,last-=y;
		flo[k]-=y,flo[k^1]+=y;
	}
	return had;
}
bool pan(int K){
	for(int i=1;i<=cnt;i++)head[i]=0;
	tail=1;
	for(int i=1;i<=n;i++){
		adlin(s,poi[i][0],K),adlin(poi[i+n][0],t,K);
		adlin(poi[i][0],poi[i][1],m),adlin(poi[i+n][1],poi[i+n][0],m);
	}
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			adlin(poi[i][like[i][j]^1],poi[j+n][like[i][j]^1],1);
		}
	}
	int ansn=0;
	while(bfs())ansn+=dfs(s,INT_MAX);
	return (ansn>=K*n);
}

signed main(){
	n=rd(),m=rd();
	s=++cnt,t=++cnt;
	for(int i=1;i<=n*2;i++)poi[i][0]=++cnt,poi[i][1]=++cnt;
	for(int i=1;i<=n;i++){
		scanf("%s",S+1);
		for(int j=1;j<=n;j++)like[i][j]=(S[j]=='Y');
	}
	int l=0,r=n,mid;
	while(l<=r){
		mid=(l+r)/2;
		if(!pan(mid))r=mid-1;
		else l=mid+1;
	}
	printf("%d",r);
	return 0;
}
posted @   flywatre  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示