[BZOJ1001][BJOI2006]狼抓兔子

这个题显然是一个最小割模型,于是快乐的打了Dinic,也就快乐的TLE了,查了查资料才知道,平面图最小割对应对偶图最短路。所谓对偶图,就是以原图中的面作为点(将s,t连接以将无界区域分成两部分),原图中的边在对偶图中变为连接相邻的面,于是,显然对偶图中s到t的一条路径代表了原图的一个割,最短路径即最小割。

code:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
 
const int N = 2000000 + 10;
const int M = 6000000 + 10;
 
int hd[N], nxt[M], to[M], w[M], cnt;
int n, m, s, t;
int dis[N], vis[N];
 
struct node {
    int pos, w;
    node (int a = 0, int b = 0) : pos(a), w(b) {}
    bool operator < (const node &x) const {
        return w > x.w;
    }
};
 
inline void Adde(int x, int y, int z) {
    cnt++;
    to[cnt] = y;
    w[cnt] = z;
    nxt[cnt] = hd[x];
    hd[x] = cnt;
} 
 
inline void adde(int x, int y, int z) {
    Adde(x, y, z);
    Adde(y, x, z);
}
 
void dij() {
    std::priority_queue<node> q;
    memset(dis, 0x3f, sizeof dis);
    dis[s] = 0;
    q.push(node(s, 0));
    node tmp;
    while (!q.empty()) {
        tmp = q.top(); q.pop();
        if (vis[tmp.pos]) continue;
        vis[tmp.pos] = 1;
        for (int i = hd[tmp.pos]; i; i = nxt[i]) {
            if (dis[to[i]] > tmp.w + w[i]) {
                dis[to[i]] = tmp.w + w[i];
                q.push(node(to[i], dis[to[i]]));
            }
        }
    }
}
 
int main () {
    scanf("%d%d", &n, &m);
    s = 0; t = 2*(n-1)*(m-1)+1;
    int w;
    if (n == 1 || m == 1) {
        if (n > m) std::swap(n, m);
        int ans = 0x3f3f3f3f;
        for (int i = 1; i < m; ++i) scanf("%d", &w), ans = std::min(ans, w);
        printf("%d\n", ans);
        return 0;
    }
    for (int i = 1; i < m; ++i) {
        scanf("%d", &w);
        adde(i*2, t, w);
    }
    for (int i = 1; i < n-1; ++i) {
        for (int j = 1; j < m; ++j) {
            scanf("%d", &w);
            adde(2*(m-1)*(i-1)+j*2-1, 2*(m-1)*i+j*2, w);
        }
    }
    for (int i = 1; i < m; ++i) {
        scanf("%d", &w);
        adde(s, 2*(m-1)*(n-2)+i*2-1, w);
    }
    for (int i = 1; i < n; ++i) {
        scanf("%d", &w);
        adde(s, 2*(m-1)*(i-1)+1, w);
        for (int j = 2; j < m; ++j) {
            scanf("%d", &w);
            adde(2*(m-1)*(i-1)+j*2-1, 2*(m-1)*(i-1)+j*2-2, w);
        }
        scanf("%d", &w);
        adde(t, 2*(m-1)*i, w);
    }
    for (int i = 1; i < n; ++i) {
        for (int j = 1; j < m; ++j) {
            scanf("%d", &w);
            adde(2*(m-1)*(i-1)+j*2, 2*(m-1)*(i-1)+j*2-1, w);
        }
    }
    dij();
    printf("%d\n", dis[t]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wyxwyx/p/bzoj1001.html