【BJOI 2006】狼抓兔子(对偶图)

题目链接

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

总结

若需要求平面图(通常是网格图)的最小割(最大流),并且数据范围极大,我们就需要使用本题中的技巧对题目进行求解。

你可能感兴趣的:(对偶图,BZOJ)