bzoj1305: [CQOI2009]dance跳舞
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
题解:
将男生i拆为两个点i1,i2,将女生j也拆为j1,j2,如果i和j互相喜欢,则由i1到j1连一条容量为1的边,否则由i2到j2连一条容量为1的边
对于男生i,由i1向i2连一条容量为k的边,对于女生j,由j2向j1连一条容量为k的边
然后二分次数tim,由S向每个男生i1连容量为tim的边,由每个女生j1向T连容量为tim的边,然后如果最大流=tim*n,则这个次数可行
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #include<cstring> 5 #include<algorithm> 6 #define maxn 250 7 #define maxm 6000 8 #define inf 1061109567 9 using namespace std; 10 char ch; 11 bool ok; 12 void read(int &x){ 13 for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 14 for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 15 if (ok) x=-x; 16 } 17 char g[55][55]; 18 int n,k,l,r,m; 19 struct flow{ 20 int s,t,tot,now[maxn],son[maxm],pre[maxm],val[maxm]; 21 int dis[maxn],head,tail,list[maxn]; 22 bool bo[maxn]; 23 void init(){s=0,t=1,tot=1,memset(now,0,sizeof(now));} 24 void put(int a,int b,int c){pre[++tot]=now[a],now[a]=tot,son[tot]=b,val[tot]=c;} 25 void add(int a,int b,int c){put(a,b,c),put(b,a,0);} 26 bool bfs(){ 27 memset(bo,0,sizeof(bo)); 28 head=0,tail=1,list[1]=s,dis[s]=0,bo[s]=1; 29 while (head<tail){ 30 int u=list[++head]; 31 for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) 32 if (val[p]&&!bo[v]) bo[v]=1,dis[v]=dis[u]+1,list[++tail]=v; 33 } 34 return bo[t]; 35 } 36 int dfs(int u,int rest){ 37 if (u==t) return rest; 38 int ans=0; 39 for (int p=now[u],v=son[p];p&&rest;p=pre[p],v=son[p]) 40 if (val[p]&&dis[v]==dis[u]+1){ 41 int d=dfs(v,min(rest,val[p])); 42 val[p]-=d,val[p^1]+=d,ans+=d,rest-=d; 43 } 44 if (!ans) dis[u]=-1; 45 return ans; 46 } 47 int dinic(){ 48 int ans=0; 49 while (bfs()) ans+=dfs(s,inf); 50 return ans; 51 } 52 }f,tmp; 53 bool check(int lim){ 54 f=tmp; 55 for (int i=1;i<=n;i++) f.add(f.s,i<<1,lim); 56 for (int i=1;i<=n;i++) f.add((i+n)<<1,f.t,lim); 57 return f.dinic()==lim*n; 58 } 59 int main(){ 60 read(n),read(k),f.init(); 61 for (int i=1;i<=n;i++) scanf("%s",g[i]+1); 62 for (int i=1;i<=n;i++) f.add(i<<1,(i<<1)+1,k); 63 for (int i=1;i<=n;i++) f.add(((i+n)<<1)+1,(i+n)<<1,k); 64 for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) 65 if (g[i][j]=='Y') f.add(i<<1,(j+n)<<1,1); 66 else f.add((i<<1)+1,((j+n)<<1)+1,1); 67 for (tmp=f,l=0,r=n,m=((l+r)>>1)+1;l<r;m=((l+r)>>1)+1) if (check(m)) l=m; else r=m-1; 68 printf("%d\n",l); 69 return 0; 70 }