BZOJ 1305: [CQOI2009]dance跳舞 二分+最大流

1305: [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

Sample Output

3

HINT

 

题解:

  建图:

  男女分别拆点x,y

  男生拆点后 有x1,x2两种,女生拆点后又y1,y2

    S - x1( 连向喜欢的人的点 )-> y1 ->T

 容量k   |             |

      x2(连向不喜欢的人的点)->y2

   其余容量为1

  二分答案,从S流出的每条边容量为mid,check 是否满流

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 100000, M = 1e3+20, mod = 1e9+7, inf = 2e9;
char mp[100][100];
int n,k,head[N],t=2,h[N],q[N],S,T,ans;
struct edge{int to,next,v;}e[N * 2];
void adds(int u,int v,int w) {e[t].to=v;e[t].v=w;e[t].next=head[u];head[u]=t++;}
void add(int u,int v,int w) {adds(u,v,w);adds(v,u,0);}
int bfs() {
    memset(h,-1,sizeof(h));
    int l=0,r=1,now;
    q[l]=S;
    h[S]=0;
    while(l!=r){
        now=q[l++];if(l == 10000) l=0;
        for(int i=head[now];i!=-1;i=e[i].next) {
            if(e[i].v&&h[e[i].to]==-1) {
                h[e[i].to]=h[now]+1;
                q[r++]=e[i].to;
                if(r==10000) r = 0;
            }
        }
    }
    if(h[T]==-1) return 0;
    else return 1;
}
int dfs(int x,int f) {
        if(x == T) return f;
        int used=0,w;
        for(int i=head[x]; i!=-1;i=e[i].next) {
            if(e[i].v&&h[e[i].to] == h[x] + 1) {
                w=dfs(e[i].to,min(f-used,e[i].v));
                used+=w;e[i].v-=w;e[i^1].v+=w;
                if(used == f) return f;
            }
        }
        return used;
}
void dinic() {while(bfs()) ans+=dfs(S,inf);}

int check(int x) {
    t = 2;S = 4*n+1, T = S+1;
    memset(head,-1,sizeof(head));
        for(int i=1;i<=n;++i) {
            add(S,i,x);
            add(i,i+n,k);
            add(2*n+i+n,i+2*n,k);
            add(2*n+i,T,x);
        }
        for(int i=1;i<=n;++i) {
            for(int j=1;j<=n;++j) {
                if(mp[i][j] == 'Y') {
                    add(i,2*n+j,1);
                }
                else add(i+n,2*n+n+j,1);
            }
        }ans = 0;
        dinic();
        if(ans == n*x) return 1;
        else return 0;
}
int main() {
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;++i) scanf("%s",mp[i]+1);
        int l = 0, r = n,ans1;
        while(l <= r) {
            int md = (l+r)>>1;
            if(check(md)) {
                ans1 = md;l = md+1;
            } else r = md-1;
        }
        printf("%d\n",ans1);
        return 0;
}
View Code

 

posted @ 2016-12-05 16:19  meekyan  阅读(163)  评论(0编辑  收藏  举报