【网络流24题】孤岛营救问题(分层图BFS)

题目描述

\(1944\) 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩。瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图。迷宫的外形是一个长方形,其南北方向被划分为 \(N\) 行,东西方向被划分为 \(M\) 列,于是整个迷宫被划分为 \(N\times M\) 个单元。每一个单元的位置可用一个有序数对(单元的行号,单元的列号)来表示。南北或东西方向相邻的 \(2\) 个单元之间可能互通,也可能有一扇锁着的门,或者是一堵不可逾越的墙。迷宫中有一些单元存放着钥匙,并且所有的门被分成\(P\) 类,打开同一类的门的钥匙相同,不同类门的钥匙不同。

大兵瑞恩被关押在迷宫的东南角,即 \((N,M)\) 单元里,并已经昏迷。迷宫只有一个入口,在西北角。也就是说,麦克可以直接进入 \((1,1)\) 单元。另外,麦克从一个单元移动到另一个相邻单元的时间为 \(1\),拿取所在单元的钥匙的时间以及用钥匙开门的时间可忽略不计。

试设计一个算法,帮助麦克以最快的方式到达瑞恩所在单元,营救大兵瑞恩。

输入格式

\(1\) 行有 \(3\) 个整数,分别表示 \(N,M,P\) 的值。

\(2\) 行是 \(1\) 个整数 \(K\),表示迷宫中门和墙的总数。

\(I+2\)\((1\leq I\leq K)\),有 \(5\) 个整数,依次为\(X_{i1},Y_{i1},X_{i2},Y_{i2},G_i\)

  • \(G_i \geq 1\) 时,表示 \((X_{i1},Y_{i1})\) 单元与 \((X_{i2},Y_{i2})\) 单元之间有一扇第 \(G_i\) 类的门

  • \(G_i=0\) 时,表示 \((X_{i1},Y_{i1})\) 单元与 \((X_{i2},Y_{i2})\) 单元之间有一堵不可逾越的墙(其中,\(|X_{i1}-X_{i2}|+|Y_{i1}-Y_{i2}|=1\)\(0\leq G_i\leq P\))。

\(K+3\) 行是一个整数 \(S\),表示迷宫中存放的钥匙总数。

\(K+3+J\)\((1\leq J\leq S)\),有 \(3\) 个整数,依次为 \(X_{i1},Y_{i1},Q_i\):表示第 \(J\) 把钥匙存放在 \((X_{i1},Y_{i1})\)单元里,并且第 \(J\) 把钥匙是用来开启第 \(Q_i\) 类门的。(其中\(1\leq Q_i\leq P\))。

输入数据中同一行各相邻整数之间用一个空格分隔。

输出格式

将麦克营救到大兵瑞恩的最短时间的值输出。如果问题无解,则输出 \(-1\)

样例 #1

样例输入 #1

4 4 9
9
1 2 1 3 2
1 2 2 2 0
2 1 2 2 0
2 1 3 1 0
2 3 3 3 0
2 4 3 4 1
3 2 3 3 0
3 3 4 3 0
4 3 4 4 0
2
2 1 2
4 2 1

样例输出 #1

14

提示

\(|X_{i1}-X_{i2}|+|Y_{i1}-Y_{i2}|=1,0\leq G_i\leq P\)

\(1\leq Q_i\leq P\)

\(N,M,P\leq10, K<150,S\leq 14\)

题解

事实上本题与网络流无关。但是建图方式对解决这类问题很有帮助。
考虑将当前坐标+当前拥有的钥匙集合定义为一个状态,则总的状态数为\(O(NM \cdot2^P)\)
这样,可以移动的相邻位置之间连边权为1的双向边,相同位置、增添一把钥匙连边权为0的边。
在边权只有0和1的图上,可以使用双端队列BFS求出最短路径。
(可是为什么直接用queue就过了呢...)

//
// Created by blackbird on 2023/8/30.
//
#include <bits/stdc++.h>
#define int long long
#define pii pair<int,int>
#define x first
#define y second
using namespace std;

const int N = 2e6 + 10, inf = 1e10;
struct node {
    int x, y, st;
} a[N];

int n, m, p;

inline int getid(int x, int y, int st) {
    return st * n * m + (x - 1) * m + y;
}

inline int ceil(int x, int y) {
    return x / y + (x % y != 0);
}


string printbit(int x) {
    string res;
    for (int i = 0; i < p; i++) {
        res.push_back('0' + (x >> i & 1));
    }
    return res;
}

void print(pii u) {
    int id = u.first;
    int st = ceil(id, n * m) - 1;
    int xy =  id % (n * m) == 0 ? n * m : id % (n * m);
    int x = ceil(xy, m);
    int y = xy - (x - 1) * m;
    cout << x << " " << y << " " << printbit(st) << " " << u.second << "\n";
}

bool ed[N];

vector<pii> g[N];
vector<int> key[21][21];

int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, 1, -1};

void solve() {
    cin >> n >> m >> p;


    for (int st = 0; st <= (1 << p) - 1; st++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                int id = getid(i, j, st);
                a[id] = {i, j, st};
                if (i == n && j == m) {
                    ed[id] = true;
                }
            }
        }
    }


    int tot; cin >> tot;
    set<pair<pii,pii>> vised;
    for (int i = 1; i <= tot; i++) {
        int x1, y1, x2, y2, c;
        cin >> x1 >> y1 >> x2 >> y2 >> c;
        c--;
        vised.insert({{x1, y1}, {x2, y2}});
        vised.insert({{x2, y2}, {x1, y1}});
        for (int st = 0; st <= (1 << p) - 1; st++) {
            int s = getid(x1, y1, st), t = getid(x2, y2, st);
            if (c < 0) continue;
            if (st >> c & 1) {
                g[s].emplace_back(t, 1);
                g[t].emplace_back(s, 1);
            }
        }
    }


    for (int st = 0; st <= (1 << p) - 1; st++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                for (int k = 0; k < 4; k++) {
                    int x = i, y = j, tx = x + dx[k], ty = y + dy[k];
                    if (tx < 1 || tx > n || ty < 1 || ty > m) continue ;
                    int s = getid(x, y, st), t = getid(tx, ty, st);
                    if (!vised.count({{x, y}, {tx, ty}})) {
                        g[s].emplace_back(t, 1);
                        g[t].emplace_back(s, 1);
                        //print({s, 0}); print({t, 0});
                    }
                }
            }
        }
    }

    cin >> tot;
    for (int i = 1; i <= tot; i++) {
        int x, y, c;
        cin >> x >> y >> c;
        c--;
        for (int st1 = 0; st1 <= (1 << p) - 1; st1++) {
            if (!(st1 >> c & 1)) {
                int st2 = st1 | (1 << c);
                int s = getid(x, y, st1), t = getid(x, y, st2);
//                print({s, 0}); print({t, 0});
//                cout << "__\n";
                g[s].emplace_back(t, 0);
                g[t].emplace_back(s, 0);
            }
        }
    }


    queue<pii> q; q.push({getid(1, 1, 0), 0});
    vector<bool> vis(N); vis[getid(1, 1, 0)] = true;
    int ans = inf;
    while (!q.empty()) {
        pii u = q.front(); q.pop(); //print(u);
        if (ed[u.first]) {
            ans = min(ans, u.second);
            continue;
        }
        for (auto &[v, w] : g[u.first]) {
            if (vis[v]) continue;
            q.push({v, u.second + w});
            vis[v] = true;
        }
    }

    if (ans == inf) ans = -1;
    cout << ans << "\n";
}

signed main() {
    //cin.tie(nullptr)->sync_with_stdio(false); srand(time(0));
    int T = 1; //cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}

posted @ 2023-08-30 18:37  _vv123  阅读(20)  评论(0编辑  收藏  举报