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

Sample Output

3
HINT

N<=50 K<=30

Source

加強數據By dwellings and liyizhen2

先把每個人i拆分成ix和iy兩個節點,ix連向喜歡的人,iy連向不喜歡的人,容量爲1(比如如果男生i與女生j互相喜歡,則由ix連向jx,如果男生i與女生j互相不喜歡,則由iy連向jy),再將每個男生男生ix連向iy,容量爲k;每個女生iy連向ix,容量爲k。由源點向每個男生的x節點連上一條邊,再由每個女生的x節點向匯點連上一條邊,容量均爲a。最後從小到大枚舉a,計算最大流flow,若發現a*n>flow(不滿流),則停止枚舉,a-1即爲答案。
(粘自hzwer,不要問我爲什麼,太懶)

#include <bits/stdc++.h>
#define inf 0x7fffffff
#define T 1001
#define N 1010
#define M 100010
using namespace std;
int head[N],q[N],h[N];
int cnt,ans, cur[N], mid, mx;
int n,k,mp[N][N];
struct Edge
{
    int next, to, v;
}e[M];

inline int read()
{
    int x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch-'0'; ch = getchar(); }
    return x * f;
}

void ins(int u, int v, int w)
{
    e[++ cnt].next = head[u];
    e[cnt].to = v;
    e[cnt].v = w;
    head[u] = cnt;
}

void insert(int u, int v, int w)
{
    ins(u, v, w);
    ins(v, u, 0);
}

int bfs()
{
    int t = 0, w = 1;
    memset(h, -1, sizeof(h));
    h[0] = 0;
    q[0] = 0;
    while(t != w)
    {
        int now = q[t ++];
        if(t == M) t = 0;
        for(int i = head[now]; i; i = e[i].next)
        {
            int y = e[i].to;
            if(h[y] == -1 && e[i].v)
            {
                h[y] = h[now] + 1;
                q[w ++] = y;
                if(w == M) w = 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; i = e[i].next)
    {
        int y = e[i].to;
        if(h[y] == h[x] + 1 && e[i].v)
        {
            w = dfs(y, min(f - used, e[i].v));
            e[i].v -= w;
            used += w;
            //if(e[i].v) cur[x] = i;
            e[i ^ 1].v += w;
            if(f == used) return used;
        }
    }
    if(used == 0) h[x] = -1;
    return used;
}

void dinic()
{
    while(bfs())
    {
        //for(int i = 0; i <= T; i ++)
        //a cur[i] = head[i];
        ans += dfs(0, inf);
    }
}

void Init()
{
    n = read();
    k = read();
    for(int i = 1; i <= n; i ++)
    {
        char ch[51];
        scanf("%s",ch);
        for(int j = 1; j <= n; j ++)
            if(ch[j - 1] == 'Y')mp[i][j] = 1;
    }
}
void build()
{
    cnt = 1;
    memset(head,0,sizeof(head));
    for(int i = 1; i <= n; i ++)insert(0, i, mid);
    for(int i = 1; i <= n; i ++)insert(i, i + 500, k);
    for(int i = 1; i <= n; i ++)insert(n + i + 500, n + i, k);
    for(int i = 1; i <= n; i ++)insert(n + i, T, mid);
    for(int i = 1; i <= n; i ++)
       for(int j = 1; j <= n; j ++)
          if(mp[i][j]) insert(i, n + j, 1);
          else insert(i + 500, n + j + 500, 1);
}
int main()
{
    Init();
    int l = 0, r = 50;
    while(l <= r)
    {
        mid = (l + r) >> 1;
        build();
        ans = 0;
        dinic();
        if(ans >= n * mid) {mx = mid; l = mid + 1;}
        else r = mid - 1;
    }
    printf("%d",mx);
    return 0;
}

發佈了85 篇原創文章 · 獲贊 6 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章