【BJOI 2006】狼抓兔子
明显是求给定的图的最小割。
但是如果直接跑最大流的话会爆炸。
我们发现这个图有一个性质:它是一个平面图(可平面图)。
我们考虑构造它的对偶图,因为对偶图的最短路即是原图的最小割。
具体构图方法见代码。
#include
#include
#include
#include
using namespace std;
const int maxn = 2000005;
const int maxm = 6000005;
char ch;
bool vis[maxn];
int n, m, x, ret, dis[maxn];
int tot, ter[maxm], nxt[maxm], len[maxm], lnk[maxn];
int read() {
ch = getchar();
ret = 0;
while (!isdigit(ch)) {
ch = getchar();
}
while (isdigit(ch)) {
ret = (ret << 1) + (ret << 3) + (ch ^ '0');
ch = getchar();
}
return ret;
}
int id(int i, int j, int k) {
if (i > n || j < 1) {
return 0;
}
if (i < 1 || j > m) {
return n * m << 1 | 1;
}
return (i - 1) * m + j + k * n * m;
}
void adde(int u, int v, int w) {
ter[tot] = v;
len[tot] = w;
nxt[tot] = lnk[u];
lnk[u] = tot++;
}
int spfa(int s, int t) {
queue<int> que;
que.push(s);
memset(dis, 0x3f, sizeof(dis));
dis[s] = s, vis[s] = 1;
for (int u, v, w; !que.empty(); ) {
u = que.front();
que.pop();
vis[u] = 0;
for (int i = lnk[u]; ~i; i = nxt[i]) {
v = ter[i], w = len[i];
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if (!vis[v]) {
vis[v] = 1;
que.push(v);
}
}
}
}
return dis[t];
}
int main() {
memset(lnk, -1, sizeof(lnk));
n = read(), m = read(), n--, m--;
for (int i = 1; i <= n + 1; i++) {
for (int j = 1; j <= m; j++) {
x = read();
adde(id(i, j, 1), id(i - 1, j, 0), x);
adde(id(i - 1, j, 0), id(i, j, 1), x);
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m + 1; j++) {
x = read();
adde(id(i, j, 0), id(i, j - 1, 1), x);
adde(id(i, j - 1, 1), id(i, j, 0), x);
}
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
x = read();
adde(id(i, j, 0), id(i, j, 1), x);
adde(id(i, j, 1), id(i, j, 0), x);
}
}
printf("%d\n", spfa(0, n * m << 1 | 1));
return 0;
}
若需要求平面图(通常是网格图)的最小割(最大流),并且数据范围极大,我们就需要使用本题中的技巧对题目进行求解。