[CQOI2009]跳舞
题目描述
一次舞会有 \(n\) 个男孩和 \(n\) 个女孩。
每首曲子开始时,所有男孩和女孩恰好配成 \(n\) 对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。
有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和 \(k\) 个不喜欢的女孩跳舞,而每个女孩也最多只愿意和 \(k\) 个不喜欢的男孩跳舞。
给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
输入格式
第一行包含两个整数 \(n\) 和 \(k\)。
以下 \(n\) 行每行包含 \(n\) 个字符,每个字符只可能是 Y
或 N
。第 \((i + 1)\) 行的第 \(j\) 个字符为 Y
当且仅当男孩 \(i\) 和女孩 \(j\) 相互喜欢。
输出格式
一行一个整数代表舞曲数目的最大值。
样例 #1
样例输入 #1
3 0
YYY
YYY
YYY
样例输出 #1
3
提示
数据规模与约定
- 对于 \(100\%\) 的数据,保证 \(1\leq n\leq 50\),\(1\leq k\leq 30\)。
题解
答案明显满足单调性,于是直接每次重新构造网络,随便跑网络流。
网络流比较重要的一点:建图要包含所有信息
#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;
}
标签:P3153,head,int,题解,fro,男孩,walk,tail,CQOI2009
From: https://www.cnblogs.com/T-water/p/16976402.html