s-t平面图最小割转最短路问题

链接:https://www.nowcoder.com/acm/contest/69/D
来源:牛客网

这是一个关于二维格子状迷宫的题目。迷宫的大小为N*M,左上角格子座标为(1,1)、右上角格子座标为(1,M)、左下角格子座标为(N,1)、右下角格子座标为(N,M)。每一格都用-1到109之间的整数表示,意义分别为:-1为墙壁,0为走道,而1到109之间的正整数代表特殊的走道。
蜥蜴最初位于迷宫的座标(1,1)的格子,每一步蜥蜴只能往上、下、左、右、左上、右上、左下、右下八个方向之一前进一格,并且,他也不能走出迷宫边界。蜥蜴的目的地是走到迷宫的右下角格子,也就是座标位置(N,M)。我们想要动一些手脚,使得蜥蜴没有办法从(1,1)出发并抵达(N,M)。我们学会了一个邪恶的法术,这个法术可以把特殊的走道变成墙壁,施法一次的代价为表示该特殊走道的正整数。
假设,我们可以在蜥蜴出发之前不限次数的使用这个邪恶的法术,所花的总代价即为每次施法代价的总和,蜥蜴出发之后就不能再使用这个法术了,请问让蜥蜴没办法达到终点所必须花费的最小总代价是多少呢?
注意,0所代表的走道是无法变为墙壁的。
输入描述:
输入的第一行有三个正整数Q,N,M。
代表接下来有Q组数据,这Q组数据都是N*M的迷宫。
接下来每组数据各N行,代表一个迷宫,每行各M个整数,第i行中的第j个整数代表迷宫座标(i,j)的格子。
输出描述:
每一组数据输出一行,如果无论如何蜥蜴都能到达终点,请在这一行中输出-1,否则请在这一行中输出一个代表答案的整数。
示例1
输入
3 3 3
0 2 2
3 2 3
2 2 0
0 1 2
-1 1 -1
2 1 0
0 1 2
0 0 0
2 1 0
输出
6
1
-1
备注:
1<=Q<=5*103
1<=Q*N*M<=2.5*105
1<=N,M<=500
代表迷宫格子的数字为介于-1和109间的整数(包含-1和109)
每个迷宫中,代表座标(1,1)和(N,M)的格子的数字一定是0

平面图的最小割是可以转成对偶图最短路的
从s-t平面图当中让原点s与汇点t连一条边,然后在构造他的对偶图G*,然后令s*为原点,t*为汇点,我们通过性质就可以得知从s*到t*的一条路径就是原图的一个割,因此s*到t*的最短路就是最小割。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 500 + 5;
const LL INF = 0x3f3f3f3f3f3f3f3f;

int n, m, a[N][N], vis[N][N];
int dir[8][2] = {1, 0, 0, 1, -1, 0, 0, -1, 1, -1, 1, 1, -1, 1, -1, -1};
LL dis[N][N];

void dfs(int x, int y) {  //判断是否连通,不连通则封不住蜥蜴
    vis[x][y] = 1;
    for (int i = 0; i < 8; ++i) {
        int nx = x + dir[i][0];
        int ny = y + dir[i][1];
        if (nx < 1 || nx > n || ny < 1 || ny > m || a[nx][ny] != 0 || vis[nx][ny]) continue;
        dfs(nx, ny);
    }
}

struct node {
    int x, y; LL d;
    node() {}
    node(int _x, int _y, LL _d): x(_x), y(_y), d(_d) {}
    bool operator < (const node &rhs) const {
        return d > rhs.d;
    }
};

LL Dij() {  //把-1变成0,0变成-1然后跑最短路
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            vis[i][j] = 0, dis[i][j] = INF;
    priority_queue <node> q;
    for (int i = 2; i <= m; ++i) if (a[1][i]) {
        q.push(node(1, i, max(a[1][i], 0)));
        dis[1][i] = max(a[1][i], 0);
    }
    for (int i = 2; i < n; ++i) if (a[i][m]) {
        q.push(node(i, m, max(a[i][m], 0)));
        dis[i][m] = max(a[i][m], 0);
    }
    while (!q.empty()) {
        node u = q.top(); q.pop();
        int x = u.x, y = u.y;
        if (vis[x][y]) continue;
        vis[x][y] = 1;
        for (int i = 0; i < 4; ++i) {
            int nx = x + dir[i][0], ny = y + dir[i][1];
            if (nx < 1 || nx > n || ny < 1 || ny > m || a[nx][ny] == 0) continue;
            if (dis[nx][ny] > dis[x][y] + max(a[nx][ny], 0)) {
                dis[nx][ny] = dis[x][y] + max(a[nx][ny], 0);
                q.push(node(nx, ny, dis[nx][ny]));
            }
        }
    }
    LL res = INF;
    for (int i = 2; i <= n; ++i) res = min(res, dis[i][1]);
    for (int i = 2; i < m; ++i) res = min(res, dis[n][i]);
    return res;
}

int main() {
    int T; scanf("%d%d%d", &T, &n, &m);
    while (T--) {
        for (int i = 1; i <= n; ++i)
            for (int j = 1; j <= m; ++j)
                scanf("%d", &a[i][j]), vis[i][j] = 0;
        dfs(1, 1);
        if (vis[n][m] == 1) {
            puts("-1");
            continue;
        }
        printf("%lld\n", Dij());
    }
}

猜你喜欢

转载自blog.csdn.net/xxxslinyue/article/details/79427666