BZOJ 1412. [ZJOI2009]狼和羊的故事

 

网络流,源点向狼连容量为 $4$ 的边,羊向汇点连容量为 $4$ 的边,然后每个格子都向四周连容量为 $1$ 的边,最小割即为答案。

#include <bits/stdc++.h>

const int N = 8e4 + 7;
struct E {
    int v, ne, f;
} e[N];
int head[N], cnt = 1, n, m, iter[N], level[N];

void add(int u, int v, int f) {
    e[++cnt].v = v; e[cnt].ne = head[u]; e[cnt].f = f; head[u] = cnt;
    std::swap(u, v);
    e[++cnt].v = v; e[cnt].ne = head[u]; e[cnt].f = f; head[u] = cnt;
}

bool bfs(int s, int t) {
    for (int i = 0; i <= t; i++) 
        iter[i] = head[i], level[i] = -1;
    level[s] = 0;
    std::queue<int> que;
    que.push(s);
    while (!que.empty()) {
        int u = que.front(); que.pop();
        for (int i = head[u]; i; i = e[i].ne) {
            int v = e[i].v, f = e[i].f;
            if (level[v] < 0 && f) {
                level[v] = level[u] + 1;
                que.push(v);
            }
        }
    }
    return level[t] != -1;
}

int dfs(int u, int f, int t) {
    if (!f || u == t) return f;
    int flow = 0;
    for (int i = iter[u]; i; i = e[i].ne) {
        iter[u] = i;
        int v = e[i].v;
        if (level[v] == level[u] + 1 && e[i].f) {
            int w = dfs(v, std::min(f, e[i].f), t);
            if (w == 0) continue;
            flow += w; f -= w;
            e[i].f -= w; e[i ^ 1].f += w;
            if (!f) break;
        }
    }
    return flow;
}

int main() {
    scanf("%d%d", &n, &m);
    int s = 0, t = n * m + 1;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            int x;
            scanf("%d", &x);
            int id = (i - 1) * m + j;
            int did = i * m + j, rid = id + 1;
            if (x == 1) add(s, id, 4);
            if (x == 2) add(id, t, 4);
            if (i < n) add(id, did, 1);
            if (j < m) add(id, rid, 1);
        }
    }
    int ans = 0;
    static const int INF = 0x3f3f3f3f;
    while (bfs(s, t))
        ans += dfs(s, INF, t);
    printf("%d\n", ans);
    return 0;
}
View Code

 

posted @ 2020-01-27 22:16  Mrzdtz220  阅读(132)  评论(0编辑  收藏  举报