孤岛营救问题

孤岛营救问题

题目链接

题目描述

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

输入输出样例

输入样例

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

输出样例

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\)

\(Solution\)

观察到数据范围很小,可以状压。

对钥匙状压,记录每个点的最短时间和相应的钥匙,然后广搜就好了。

似乎没有什么好说的。代码详解。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
long long read(){
    long long x = 0; int f = 0; char c = getchar();
    while(c < '0' || c > '9') f |= c == '-', c = getchar();
    while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    return f? -x:x;
}

int dir[4][2] = {{0, -1}, {0, 1}, {-1, 0}, {1, 0}};//记录方向
int n, m, p, k, a, b, c, d, e;
int key[22][22], wall[22][22][4], vis[1024][22][22];
    //每个点的钥匙   墙的状态       是否访问过
struct szh{
    int key, x, y, d;//广搜结构体
};
queue<szh> q;
int main(){
    n = read(); m = read(); p = read(); k = read();
    while(k--){
        a = read(); b = read(); c = read(); d = read(); e = read();
        if(!e--) e = 11;//墙特殊处理
        for(int i = 0; i < 4; i++)//找方向
            if(c == a + dir[i][0] && d == b + dir[i][1]){
                wall[a][b][i] = 1 << e,wall[c][d][i ^ 1] = 1 << e;//两个点都要更新
                break;
            }
    }
    k = read();
    while(k--){
        a = read(); b = read(); c = read();
        key[a][b] |= 1 << (c - 1);//状压钥匙
    }
    q.push((szh){key[1][1], 1, 1, 0});//起点入队
    while(!q.empty()){
        szh u = q.front(); q.pop();
        int ky = u.key, x = u.x, y = u.y, d = u.d;
        if(x == n && y == m){//走到终点就退出
            printf("%d\n", d);return 0;
        }
        for(int i = 0; i < 4; i++){//遍历四个方向
            if((wall[x][y][i] & ky) != wall[x][y][i]) continue;//没对应钥匙
            int nx = x + dir[i][0], ny = y + dir[i][1], nky = ky | key[nx][ny];
            if(nx < 1 || ny < 1 || nx > n || ny > m) continue;//越界
            if(!vis[nky][nx][ny])//入队
                vis[nky][nx][ny] = 1, q.push((szh){nky, nx, ny, d + 1});
        }
    }
    puts("-1");
    return 0;
}

原文地址:https://www.cnblogs.com/kylinbalck/p/10617877.html

时间: 2024-08-28 15:28:48

孤岛营救问题的相关文章

【网络流24题----14】孤岛营救问题

孤岛营救问题 Time Limit: 1 Sec  Memory Limit: 128 MB Description 1944年,特种兵麦克接到国防部的命令.要求马上赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图.迷宫的外形是一个长方形,其南北方向被划分为 N行,东西方向被划分为 M列,于是整个迷宫被划分为 N×M个单元.每个单元的位置可用一个有序数对 (单元的行号,单元的列号)来表示.南北或东西方向相邻的 2个单元之间可能互

【线性规划与网络流24题】孤岛营救问题 分层图

孤岛营救问题 Time Limit: 1 Sec  Memory Limit: 128 MB Description 1944年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但幸好麦克得到了迷宫的地形图.迷宫的外形是一个长方形,其南北方向被划分为 N行,东西方向被划分为 M列,于是整个迷宫被划分为 N×M个单元.每一个单元的位置可用一个有序数对 (单元的行号,单元的列号)来表示.南北或东西方向相邻的 2个单元之间可能

【网络流24题】 No.14 孤岛营救问题 (分层图最短路)

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

【CTSC1999】拯救大兵瑞恩(孤岛营救问题)

2219 拯救大兵瑞恩 1999年CTSC国家队选拔赛 时间限制: 1 s 空间限制: 64000 KB 题目等级 : 大师 Master 题目描述 Description 1944年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一个孤岛,营救被敌军俘虏的大兵瑞恩.瑞恩被关押在一个迷宫里,迷宫地形复杂,但是幸好麦克得到了迷宫的地形图. 迷宫的外形是一个长方形,其在南北方向被划分为N行,在东西方向被划分为M列,于是整个迷宫被划分为N*M个单元.我们用一个有序数对(单元的行号,单元的列号)来表

【codevs 1911 孤岛营救问题】

·为了分析方便,可以先做一个题目简化.去掉"钥匙"这个条件,那么就是一个BFS或者SPFA--现在加上该条件.如本题只给出最多两种钥匙,当然你可以继续坚持BFS等方式,时间不会太差.但是一旦钥匙种类上升至15的时候,就有太多情况需要处理(光说你写BFS的if就是很长的过程,但个人认为时间复杂度依旧能过这道题). ·如图是简化版本的决策方式(为与后文呼应,用SPFA): 大方块是整个地图.小方块是一个房间.那么你可以在向四个方向走,前提是有路可走(没有墙).你本可以轻松拯救大兵瑞恩,然后

网络流24题 之十四 孤岛营救问题 分层图

题目大意:一张网格图,上面有一些点可能有某种钥匙.节点和节点之间可能有门.有些门须要特定的钥匙就能够通过,有些不管怎样都过不去.求从(1,1)開始到(m,n)的最短时间. 思路:分层图+状态压缩. f[i][j][k],当中i和j描写叙述的是当前所在的位置.k是压缩了的当前有哪些钥匙(因为钥匙的数量<=10,所以全部的状态1<<10的空间内就能够搞定).然后向四个方向更新的时候推断能否经过门. CODE: #include <queue> #include <cstdi

洛谷 [P4011] 孤岛营救问题

状压+BFS 通过观察数据范围可知,我们应该状压钥匙种类,直接BFS即可 注意,一个点处可能不知有一把钥匙 #include <iostream> #include <cstdio> #include <algorithm> #include <cstdlib> #include <queue> using namespace std; bool f[14][14][1200]; int n,m,p,k,s,key[15][15],block1[

洛谷 P4011 孤岛营救问题【bfs】

注意: 一个点可能有多把钥匙,所以把每个点有钥匙的情况状压一下 两个点之间有障碍的情况只给出了单向,存的时候记得存一下反向 b[i][j]表示当前点拥有钥匙的状态,g[x1][y1][x2][y2]表示两点之间门的类型(0表示没有,-1表示墙比较方便),f[i][j][k]表示点(i,j)在拥有k状态钥匙的情况下的最小步数,v[i][j][k]表示f[i][j][k]的状态是否在bfs队列里.然后转移比较类似spfa 以及终于知道为什么这种题会在24题里了-因为24全名"网络流与线性规划二十四题

[题解]luogu_P4011_孤岛营救问题(状压bfs/最短路

钥匙只有10种可以状压,最短路或者bfs都行,但是写挂了(现在还是 #include<iostream> #include<cstdio> #include<cstring> #include<queue> #define pb push_back using namespace std; const int maxn=13; const int dx[]={-1,0,1,0}; const int dy[]={0,1,0,-1}; int n,m,p,k,