题目链接<https://cn.vjudge.net/problem/HYSBZ-1305>
题解:
男生拆成两个点,x1,y1。建边<x1,y1>=k。
女生拆成两个点,x2,y2。建边<y2,x2>=k。
如果互相喜欢,<x1,x2>=1。不喜欢<y1,y2>=1。
二分答案建边<s,x1>=<x2,t> = mid。
每次二分做dinic判断都需要重新建一遍图。
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#include<iostream>
using namespace std;
const int N=1e5+7;
const int MAX=1<<26;
const int inf=1e5+7;
struct Edge{
int u,v,w,next;
Edge(int u=0,int v=0,int w=0,int next=0):u(u),v(v),w(w),next(next){}
}edge[10*N];
int n,k,edn,sp,tp;
int p[N],d[N],c[N];
void addedge(int u,int v,int w){
edge[edn]=Edge(u,v,w,p[u]);p[u]=edn++;
edge[edn]=Edge(v,u,0,p[v]);p[v]=edn++;
}
bool bfs(){
memset(d,-1,sizeof(d));d[sp]=0;
queue<int>q;q.push(sp);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=p[u];~i;i=edge[i].next){
int v=edge[i].v;
if(d[v]==-1&&edge[i].w){
d[v]=d[u]+1;
q.push(v);
if(v==tp) return true;
}
}
}
return ~d[tp];
}
int dfs(int u,int b){
if(u==tp) return b;
int r=0;
for(int i=c[u];~i;i=edge[i].next){
int v=edge[i].v;
if(edge[i].w&&d[v]==d[u]+1){
int x=min(edge[i].w,b-r);
c[u]=i;
x=dfs(v,x);
r+=x;
edge[i].w-=x;
edge[i^1].w+=x;
if(r==b) break;
}
}
if(!r)d[u]=-2;
return r;
}
int dinic(){
int total=0,t;
while(bfs()){
memcpy(c,p,sizeof(p));
while(t=dfs(sp,MAX))
total+=t;
}
return total;
}
char mt[55][55];
bool build(int mid){
memset(p,-1,sizeof(p));edn=0;
for(int i=0;i<n;i++){
addedge(i,i+n,k);
addedge(i+3*n,i+2*n,k);
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(mt[i][j]=='Y') addedge(i,j+2*n,1);
else addedge(i+n,j+3*n,1);
}
}
for(int i=0;i<n;i++){
addedge(sp,i,mid);
addedge(i+2*n,tp,mid);
}
}
int main()
{
scanf("%d%d",&n,&k);
sp=5*n;tp=sp+1;
for(int i=0;i<n;i++)
scanf("%s",mt[i]);
int lo=0,hi=n;
while(lo<=hi){
int mid=(lo+hi)>>1;
build(mid);
if(dinic()>=mid*n) lo=mid+1;
else hi=mid-1;
}
printf("%d\n",hi);
return 0;
}