题目链接
题解
如果只有 1 1 和的话,那么就将源点连羊,狼连汇点(容量 inf inf ),狼羊之间连一条容量为 1 1 的边。
但是,有的领地既不是羊的,也不是狼的。
你可能会想把归为
1
1
(或),但是仔细想想可以发现还有更优的解。
最终的解决方案: 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;
}