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; }