[BZOJ1305][CQOI2009]跳舞(网络流)

1305: [CQOI2009]dance跳舞

Time Limit: 5 Sec  Memory Limit: 162 MB
Submit: 3944  Solved: 1692
[Submit][Status][Discuss]

Description

一 次舞会有n个男孩和n个女孩。每首曲子开始时,所有男孩和女孩恰好配成n对跳交谊舞。每个男孩都不会和同一个女孩跳两首(或更多)舞曲。有一些男孩女孩相 互喜欢,而其他相互不喜欢(不会“单向喜欢”)。每个男孩最多只愿意和k个不喜欢的女孩跳舞,而每个女孩也最多只愿意和k个不喜欢的男孩跳舞。给出每对男 孩女孩是否相互喜欢的信息,舞会最多能有几首舞曲?

Input

第一行包含两个整数n和k。以下n行每行包含n个字符,其中第i行第j个字符为'Y'当且仅当男孩i和女孩j相互喜欢。

Output

仅一个数,即舞曲数目的最大值。

Sample Input

3 0
YYY
YYY
YYY

Sample Output

3

HINT

N<=50 K<=30

Source

[Submit][Status][Discuss]

显然是一个二分图匹配的问题,将每个人拆成两个点:喜欢点i和讨厌点i',每个限制依次考虑:

1.一对只跳一次:喜欢则i和j连1的边,讨厌则i'和j'连1的边。

2.讨厌至多k个:i向i'连k的边,j'向j连k的边。

3.但是这样直接跑之后并不能得到结果,因为不保证同性之间没有冲突,所以必须二分答案mid,S向i连mid边,j向T连mid边。

跑$O(\log n)$次最大流即可。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rep(i,l,r) for (int i=l; i<=r; i++)
 5 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 6 using namespace std;
 7 
 8 const int N=1010,M=500100,inf=0x3f3f3f3f;
 9 char ch;
10 int n,k,cnt,ans,mx,mid,S,T,d[N],q[M],h[N],f[M],nxt[M],to[M],mp[N][N];
11 
12 void add(int u,int v,int w){
13     to[++cnt]=v; f[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt;
14     to[++cnt]=u; f[cnt]=0; nxt[cnt]=h[v]; h[v]=cnt;
15 }
16 
17 int bfs(){
18     rep(i,0,T) d[i]=0; d[S]=1; q[1]=S;
19     for (int st=0,ed=1; st!=ed; ){
20         int x=q[++st];
21         For(i,x) if (!d[k=to[i]] && f[i]) q[++ed]=k,d[k]=d[x]+1;
22     }
23     return d[T];
24 }
25 
26 int dfs(int x,int lim){
27     if (x==T) return lim;
28     int c=0,t;
29     For(i,x) if (d[k=to[i]]==d[x]+1 && f[i]){
30         t=dfs(k,min(lim-c,f[i]));
31         f[i]-=t; f[i^1]+=t; c+=t;
32         if (c==lim) return lim;
33     }
34     if (!c) d[x]=-1;
35     return c;
36 }
37 
38 void build(){
39     cnt=1; memset(h,0,sizeof(h));
40     S=4*n+1,T=4*n+2;
41     rep(i,1,n) add(S,i,mid),add(i,i+n,k),add(i+2*n,i+3*n,k),add(i+3*n,T,mid);
42     rep(i,1,n) rep(j,1,n) if (mp[i][j]) add(i,j+3*n,1); else add(i+n,j+2*n,1);
43 }
44 
45 int main(){
46     freopen("bzoj1305.in","r",stdin);
47     freopen("bzoj1305.out","w",stdout);
48     scanf("%d%d",&n,&k);
49     rep(i,1,n) rep(j,1,n) scanf(" %c",&ch),mp[i][j]=(ch=='Y');
50     int L=0,R=n;
51     while (L<=R){
52         mid=(L+R)>>1; build();
53         ans=0; while (bfs()) ans+=dfs(S,inf);
54         if (ans>=n*mid) mx=mid,L=mid+1; else R=mid-1;
55     }
56     printf("%d\n",mx);
57     return 0;
58 }

 

posted @ 2018-04-10 18:48  HocRiser  阅读(228)  评论(0编辑  收藏  举报