【BJOI 2006】狼抓兔子(對偶圖)
阿新 • • 發佈:2019-01-29
題目連結
題解
明顯是求給定的圖的最小割。
但是如果直接跑最大流的話會爆炸。
我們發現這個圖有一個性質:它是一個平面圖(可平面圖)。
我們考慮構造它的對偶圖,因為對偶圖的最短路即是原圖的最小割。
具體構圖方法見程式碼。
程式碼
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
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;
}
總結
若需要求平面圖(通常是網格圖)的最小割(最大流),並且資料範圍極大,我們就需要使用本題中的技巧對題目進行求解。