1305: [CQOI2009]dance跳舞
Time Limit: 5 Sec Memory Limit: 162 MBSubmit: 1586 Solved: 666
[ Submit][ Status]
Description
一次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?
Input
第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为'Y'当且仅当男孩i和女孩j相互喜欢。
Output
仅一个数,即舞曲数目的最大值。
Sample Input
3 0
YYY
YYY
YYY
YYY
YYY
YYY
Sample Output
3
HINT
N<=50 K<=30
Source
二分/枚举+网络流
我是用枚举歌曲数为x来做的(枚举每次只要把一些边的流量+1,在原图上继续增广;而二分需要重新构图,重新增广)
我把每个人拆成了3个点a,b,c:a是总点,b是喜欢点,c是不喜欢点。
如果男生i喜欢女生j,则ib,jb连流量为1的边;如果不喜欢则ic,jc连流量为1的边。
对于每个男生的a点与s连流量为x的边,女生的a点与t连流量为x的。
每个人的a与b之间连流量为n的边,a与c之间连流量为k的边。
直接跑最大流,看是否满流,不满流则输出结果。
其实这道题的a点和b点可以合并成一个点的。。
0ms的贪心做法是错误的:
3 0
YYY
YNN
YNN这组数据答案为0,贪心跑出来是1。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <queue>
#define M 1005
#define inf 0x3f3f3f3f
using namespace std;
char st[100];
int h[M],flow,cur[M],v[M],d[M],s,t,n,k,tot=1;
struct edge
{
int from,to,cap,flow,ne;
}E[M*200];
void Addedge(int from,int to,int cap)
{
E[++tot]=(edge){from,to,cap,0,h[from]};
h[from]=tot;
E[++tot]=(edge){to,from,0,0,h[to]};
h[to]=tot;
}
bool bfs()
{
queue<int> q;
q.push(s);
memset(v,0,sizeof(v));
v[s]=1,d[s]=0;
while (!q.empty())
{
int x=q.front();
q.pop();
for (int i=h[x];i;i=E[i].ne)
{
edge e=E[i];
if (!v[e.to]&&e.cap>e.flow)
{
v[e.to]=1;
q.push(e.to);
d[e.to]=d[x]+1;
}
}
}
return v[t];
}
int dfs(int x,int a)
{
int flow=0;
if (x==t||!a) return a;
for (int &i=cur[x];i;i=E[i].ne)
{
edge &e=E[i];
if (d[e.to]!=d[x]+1) continue;
int f=dfs(e.to,min(e.cap-e.flow,a));
if (f>0)
{
e.flow+=f;
E[i^1].flow-=f;
flow+=f;
a-=f;
if (!a) break;
}
}
return flow;
}
void dinic()
{
while (bfs())
{
for (int i=s;i<=t;i++)
cur[i]=h[i];
flow+=dfs(s,inf);
}
}
int main()
{
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++)
{
scanf("%s",st);
for (int k=0;k<n;k++)
{
int j=k+1;
if (st[k]=='Y') Addedge(2*n+i,3*n+j,1);
else Addedge(4*n+i,5*n+j,1);
}
}
s=0,t=6*n+1;
for (int i=1;i<=n;i++)
Addedge(i,4*n+i,k),Addedge(5*n+i,n+i,k),
Addedge(i,2*n+i,n),Addedge(3*n+i,n+i,n);
int be=0;
for (int i=1;i<=n;i++)
{
if (i==1) be=tot+1;
Addedge(s,i,0);
Addedge(n+i,t,0);
}
int ans=0;
flow=0;
while (1)
{
for (int i=be;i<=tot;i+=2)
E[i].cap++;
dinic();
if (flow==(ans+1)*n) ans++;
else break;
}
printf("%d\n",ans);
return 0;
}
感悟:
一开始建图的+-写错了,wa好多次。。