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

题目描述

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

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

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

输入格式

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

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

I+2(1IK),有 5 个整数,依次为Xi1,Yi1,Xi2,Yi2,Gi

  • Gi1 时,表示 (Xi1,Yi1) 单元与 (Xi2,Yi2) 单元之间有一扇第 Gi 类的门

  • Gi=0 时,表示 (Xi1,Yi1) 单元与 (Xi2,Yi2) 单元之间有一堵不可逾越的墙(其中,|Xi1Xi2|+|Yi1Yi2|=10GiP)。

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

K+3+J(1JS),有 3 个整数,依次为 Xi1,Yi1,Qi:表示第 J 把钥匙存放在 (Xi1,Yi1)单元里,并且第 J 把钥匙是用来开启第 Qi 类门的。(其中1QiP)。

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

输出格式

将麦克营救到大兵瑞恩的最短时间的值输出。如果问题无解,则输出 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

提示

|Xi1Xi2|+|Yi1Yi2|=1,0GiP

1QiP

N,M,P10,K<150,S14

题解

事实上本题与网络流无关。但是建图方式对解决这类问题很有帮助。
考虑将当前坐标+当前拥有的钥匙集合定义为一个状态,则总的状态数为O(NM2P)
这样,可以移动的相邻位置之间连边权为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 @   _vv123  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
历史上的今天:
2020-08-30 NMET Math Note 1 新百年解析几何
点击右上角即可分享
微信分享提示