題目鏈接
題解
如果只有 和 的話,那麼就將源點連羊,狼連匯點(容量 ),狼羊之間連一條容量爲 的邊。
但是,有的領地既不是羊的,也不是狼的。
你可能會想把 歸爲 (或 ),但是仔細想想可以發現還有更優的解。
最終的解決方案: 點與四周的所有節點連一條邊,這樣就可以在 的四周自由切割,沒有附加限制。
代碼
#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;
}