一开始倒没把模型建对。。
我们把每个人x拆为x1和x2两点,x1表示和喜欢的人跳舞,x2表示和不喜欢的人跳舞。那么若男生i和女生j互相喜欢,i1向j1连容量1的边;若不喜欢,i2向j2连容量1的边,每男生x由x1向x2连容量k的边,每个女生y由y2向y1连容量k的边,表示和不喜欢的人跳舞次数的限制。。
接下来从1开始枚举答案,初始时源到男生x1,女生y1到汇的边容量都为0,每次将这些边的容量都加1,若增广流大小为n,那么说明当前答案是可以达到的。。
还可以二分答案,只是每次要重构图,我觉得会更慢吧。。
#include<iostream>
#include<cstdio>
#define N 205
#define inf 0x3f3f3f3f
using namespace std;
struct edge{
int e,f,next;
}ed[N*N*2];
int n,k,i,j,ne=1,nd,ans,st,top=0,a[N],d[N],u[N],que[N],s[N];
char ch;
void add(int s,int e,int f)
{
ed[++ne].e=e;ed[ne].f=f;
ed[ne].next=a[s];a[s]=ne;
}
bool bfs(int s,int t)
{
int head=1,tail=1,get,i,j,to;
for (i=0;i<=nd;i++) d[i]=0,u[i]=0;
que[1]=s;u[s]=1;
while (head<=tail)
{
get=que[head++];
for (j=a[get];j;j=ed[j].next)
if (ed[j].f&&!u[to=ed[j].e])
{
d[to]=d[get]+1;
u[to]=1;
que[++tail]=to;
}
}
return d[t]!=0;
}
int extend(int x,int minf,int t)
{
if (x==t) return minf;
int f=minf,j,del;
for (j=a[x];j;j=ed[j].next)
if (ed[j].f&&d[ed[j].e]==d[x]+1)
{
del=extend(ed[j].e,min(minf,ed[j].f),t);
ed[j].f-=del;ed[j^1].f+=del;
minf-=del;
if (!minf) break;
}
if (f==minf) d[x]=0;
return f-minf;
}
int dinic(int s,int t)
{
int ans=0;
while (bfs(s,t)) ans+=extend(s,inf,t);
return ans;
}
int main()
{
freopen("1305.in","r",stdin);
scanf("%d%d\n",&n,&k);
nd=4*n+1;
for (i=0;i<=nd;i++) a[i]=0;
for (i=1;i<=n;i++)
{
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 (j=1;j<=n;j++)
{
scanf("%c",&ch);
if (ch=='Y') add(i,2*n+j,1),add(2*n+j,i,0);
else add(i+n,j+3*n,1),add(j+3*n,i+n,0);
}
scanf("\n");
}
ans=1;st=ne+1;
for (i=1;i<=n;i++) add(0,i,0),add(i,0,0),add(i+2*n,nd,0),add(nd,i+2*n,0);
while (1)
{
for (i=st;i<=ne;i+=2) ed[i].f++;
if (dinic(0,nd)==n) ans++;else break;
}
printf("%d\n",ans-1);
}