P3153 [CQOI2009]跳舞
考虑建模
将男生和女生分别拆成两个点 (喜欢、不喜欢)
二分容量,跑满了则增大
\(S\)向男生喜欢连\(mid\)容量,男生喜欢向男生不喜欢连\(k\)容量
女生拆成的点同理
按矩阵,喜欢向喜欢,不喜欢向不喜欢连容量为\(1\)的边
My complete
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
using namespace std;
typedef long long LL;
const LL maxn=50000;
const LL inf=0x3f3f3f3f;
inline LL Read(){
LL x=0,f=1; char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<3)+(x<<1)+c-'0'; c=getchar();
}return x*f;
}
struct node{
LL to,next,flow;
}dis[maxn];
LL n,K,num,S,T,ans;
LL head[maxn],dep[maxn];
char s[100][100];
inline void Add(LL u,LL v,LL flow){
dis[++num]=(node){v,head[u],flow}; head[u]=num;
}
inline LL Bfs(){
queue<LL> que;
que.push(S);
memset(dep,0,sizeof(dep));
dep[S]=1;
while(que.size()){
LL u=que.front(); que.pop();
for(LL i=head[u];i!=-1;i=dis[i].next){
LL v=dis[i].to;
if(!dep[v]&&dis[i].flow){
dep[v]=dep[u]+1;
que.push(v);
}
}
}
return dep[T];
}
LL Dinic(LL u,LL flow){
if(u==T)
return flow;
LL tmp=flow;
for(LL i=head[u];i!=-1;i=dis[i].next){
LL v=dis[i].to;
if(tmp&&dis[i].flow&&dep[v]==dep[u]+1){
LL now=Dinic(v,min(tmp,dis[i].flow));
if(now){
dis[i].flow-=now;
dis[i^1].flow+=now;
tmp-=now;
}else
dep[v]=inf;
}
}
return flow-tmp;
}
inline LL Solve(){
LL sum=0;
while(Bfs())
sum+=Dinic(S,inf);
return sum;
}
inline bool Check(LL mid){
S=0; T=4*n+1;
memset(head,-1,sizeof(head));
num=-1;
for(LL i=1;i<=n;++i){
Add(S,i,mid),Add(i,S,0);
Add(i+2*n,T,mid),Add(T,i+2*n,0);
Add(i,i+n,K),Add(i+n,i,0);
Add(i+3*n,i+2*n,K),Add(i+2*n,i+3*n,0);
}
for(LL i=1;i<=n;++i){
for(LL j=1;j<=n;++j){
if(s[i][j]=='Y'){
Add(i,j+2*n,1),Add(j+2*n,i,0);
}else{
Add(i+n,j+3*n,1),Add(j+3*n,i+n,0);
}
}
}
if(Solve()==n*mid)
return true;
return false;
}
int main(){
n=Read(),K=Read();
for(LL i=1;i<=n;++i)
scanf(" %s",s[i]+1);
LL l=0,r=n;
while(l<=r){
LL mid=(l+r)>>1;
if(Check(mid)){
ans=mid;
l=mid+1;
}else
r=mid-1;
}
printf("%lld",ans);
}/*
3 0
YYY
YYY
YYY
3
*/