【ZJOI 2009】狼和羊的故事(最小割)

題目鏈接

【ZJOI 2009】狼和羊的故事


題解

如果只有12 的話,那麼就將源點連羊,狼連匯點(容量inf ),狼羊之間連一條容量爲1 的邊。

但是,有的領地既不是羊的,也不是狼的。
你可能會想把0 歸爲1 (或2 ),但是仔細想想可以發現還有更優的解。

最終的解決方案:0 點與四周的所有節點連一條邊,這樣就可以在0 的四周自由切割,沒有附加限制。


代碼

#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int maxl = 105;
const int maxn = 10005;
const int maxm = 60005;
const int inf = 1000000000;
int n, m, src, snk, c[maxl][maxl], dis[maxn];
int tot, ter[maxm], len[maxm], nxt[maxm], lnk[maxn];
int id(int i, int j) {
    return (i - 1) * m + j;
}
void add(int u, int v, int w) {
    ter[tot] = v;
    len[tot] = w;
    nxt[tot] = lnk[u];
    lnk[u] = tot++;
}
void adde(int u, int v, int w) {
    add(u, v, w);
    add(v, u, w);
}
int min(int x, int y) {
    return x < y ? x : y;
}
bool bfs(int s, int t) {
    queue<int> que;
    que.push(s);
    memset(dis, -1, sizeof(dis));
    dis[s] = 0;
    for (int u, v, w; !que.empty(); ) {
        u = que.front();
        que.pop();
        for (int i = lnk[u]; ~i; i = nxt[i]) {
            v = ter[i], w = len[i];
            if (w && dis[v] == -1) {
                dis[v] = dis[u] + 1;
                que.push(v);
            }
        }
    }
    return ~dis[t];
}
int find(int u, int lft) {
    if (u == snk) {
        return lft;
    }
    int tmp, res = 0;
    for (int v, w, i = lnk[u]; ~i && res < lft; i = nxt[i]) {
        v = ter[i], w = len[i];
        if (w && dis[u] + 1 == dis[v]) {
            tmp = find(v, min(w, lft - res));
            if (tmp) {
                len[i] -= tmp;
                len[i ^ 1] += tmp;
                res += tmp;
            }
        }
    }
    if (res < lft) {
        dis[u] = -1;
    }
    return res;
}
int dinic() {
    int tmp, res = 0;
    while (bfs(src, snk)) {
        tmp = find(src, inf);
        while (tmp) {
            res += tmp;
            tmp = find(src, inf);
        }
    }
    return res;
}
int main() {
    memset(lnk, -1, sizeof(lnk));
    scanf("%d %d", &n, &m);
    src = 0, snk = n * m + 1;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            scanf("%d", c[i] + j);
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (c[i][j] == 1) {
                adde(src, id(i, j), inf);
            } else if (c[i][j] == 2) {
                adde(id(i, j), snk, inf);
            }
        }
    }
    for (int i = 1; i < n; i++) {
        for (int j = 1; j <= m; j++) {
            if (c[i][j] == c[i + 1][j] && c[i][j]) {
                continue;
            }
            adde(id(i, j), id(i + 1, j), 1);
        }
    }
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j < m; j++) {
            if (c[i][j] == c[i][j + 1] && c[i][j]) {
                continue;
            }
            adde(id(i, j), id(i, j + 1), 1);
        }
    }
    printf("%d\n", dinic());
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章