HDU 4560解題報告

根據題目的意思,我們設比賽場次爲c,二分這個場次,然後建邊跑網絡流,看看最後流量能不能等於n*c即可。
建邊是最難得地方。。
源點s,匯點t
因爲每個人要演出c次,那麼s向每個歌手連一條容量爲c的邊。
把每個流派拆成兩個點k, k’點分別表示擅長和不擅長的點
那麼每個歌手向k和k’都連一條容量爲1的邊,表示每場次演唱一首歌。
然後k’點向k點連一條容量爲C(限制)的邊,表示整個演唱場次下來,第k流派的最大觀衆容忍度。
然後k向匯點連一條容量爲c的邊

/*
納蘭性德 -清
《長相思·山一程》
山一程,水一程,身向榆關那畔行,夜深千帳燈。
風一更,雪一更,聒碎鄉心夢不成,故園無此聲。
*/
//  Created by Matrix on 2016-02-02
//  Copyright (c) 2015 Matrix. All rights reserved.
//
//
//#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <sstream>
#include <set>
#include <vector>
#include <stack>
#define ALL(x) x.begin(), x.end()
#define INS(x) inserter(x, x,begin())
#define ll long long
#define CLR(x) memset(x, 0, sizeof x)
using namespace std;
const int inf = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const int maxn = 2e4 + 10;
const int maxv = 1e3 + 10;
const double eps = 1e-9;


int n, m, l, k;
int head[maxv], nxt[maxn], cap[maxn], pnt[maxn], cnt;
void add_edge(int u, int v, int c) {
    pnt[cnt] = v;
    cap[cnt] = c;
    nxt[cnt] = head[u];
    head[u] = cnt++;
}
void add(int u, int v, int c) {
    add_edge(u, v, c);
    add_edge(v, u, 0);
}
int level[maxv], cur[maxv];
bool bfs(int s, int t) {
    memset(level, -1, sizeof level);
    queue <int> que;
    level[s] = 0;
    que.push(s);
    while(que.size() && level[t] == -1) {
        int u = que.front(); que.pop();
        for(int i = head[u]; ~i; i = nxt[i]) {
            int v = pnt[i];
            if(cap[i] > 0 && level[v] == -1) {
                level[v] = level[u] + 1;
                que.push(v);
            }
        }
    }
    return level[t] != -1;
}

int dfs(int u, int t, int f) {
    if(u == t) return f;
    int left = f;
    for(int i = cur[u]; ~i; i = nxt[i]) {
        int v = pnt[i];
        if(cap[i] > 0 && level[v] == level[u] + 1) {
            int d = dfs(v, t, min(left, cap[i]));
            cap[i] -= d;
            cap[i^1] += d;
            cur[u] = i; //當前弧優化
            left -= d; //多路增廣
            if(!left) return f;
        }
    }
    level[u] = -1;
    return f - left;
}
int dinic(int st, int ed) {
    int ans = 0;
    while(bfs(st, ed)) {
        for(int i = st; i <= ed; i++) cur[i] = head[i];
        ans += dfs(st, ed, inf);
    }
    return ans;
}
int mp[maxv][maxv];
int st, ed;
bool check(int c) {
    memset(head, -1, sizeof head);
    cnt = 0;
    for(int i = 1; i <= n; i++) {
        add(st, i, c);
        for(int j = 1; j <= m; j++) {
            if(mp[i][j]) {
                add(i, j + n, 1);
            }
            else add(i, j + n + m, 1);
        }
    }
    for(int i = n + 1; i <= n + m; i++) {
        add(i + m, i, k);
        add(i, ed, c);
    }
    return dinic(st, ed) >= n * c;
}
int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//  freopen("out.txt","w",stdout);
#endif
    int cas = 0, T;
    scanf("%d", &T);
    while(T--) {
        CLR(mp);
        scanf("%d%d%d%d", &n, &m, &l, &k);
        for(int i = 1; i <= l; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            mp[u][v] = 1;
        }
        st = 0, ed = n + m * 2 + 1;
        int l = 0, r = m;
        while(l <= r) {
            int mid = (l + r) / 2;
            if(check(mid)) l = mid + 1;
            else r = mid - 1;
        }
        printf("Case %d: %d\n", ++cas, l - 1);
    }

    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章