我是靠谱客的博主 含糊日记本,最近开发中收集的这篇文章主要介绍codevs 1911孤岛营救问题/2219拯救大兵瑞恩,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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

大兵瑞恩被关押在迷宫的东南角,即(N,M)单元里,并已经昏迷。迷宫只有一个入口,
在西北角。也就是说,麦克可以直接进入(1,1)单元。另外,麦克从一个单元移动到另一个
相邻单元的时间为1,拿取所在单元的钥匙的时间以及用钥匙开门的时间可忽略不计。
«编程任务:
试设计一个算法,帮助麦克以最快的方式到达瑞恩所在单元,营救大兵瑞恩。
输入描述 Input Description
第1行有3个整数,分别表示N,M,P的值。第2 行是1
个整数K,表示迷宫中门和墙的总数。第I+2 行(1<=I<=K),有5 个整数,依次为
Xi1,Yi1,Xi2,Yi2,Gi:
当Gi>=1时,表示(Xi1,Yi1)单元与(Xi2,Yi2)单元之间有一扇第Gi类的门,当Gi=0 时,
表示(Xi1,Yi1)单元与(Xi2,Yi2)单元之间有一堵不可逾越的墙(其中,|Xi1-Xi2|+|Yi1-Yi2|=1,
0<=Gi<=P)。
第K+3行是一个整数S,表示迷宫中存放的钥匙总数。
第K+3+J 行(1<=J<=S),有3个整数,依次为Xi1,Yi1,Qi:表示第J 把钥匙存放在(Xi1,Yi1)
单元里,并且第J 把钥匙是用来开启第Qi类门的。(其中1<=Qi<=P)。
输入数据中同一行各相邻整数之间用一个空格分隔。
输出描述 Output Description
将麦克营救到大兵瑞恩的最短时间的值输出。如果问题无解,则输出-1。
样例输入 Sample Input
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
样例输出 Sample Output
14

其实这道题先前做kac的迷宫的时候接触过,但这道题稍难一些

题目大意是要在地图上有一些单元之间两两有墙,如果有相应的钥匙就可以开门(墙),但有些墙是开不了的,即使有钥匙也不行QAQ
这样的话就可以使用bfs来解决这道题
在搜索过程中保存坐标和已拥有的钥匙数
类似分层的思想,拥有不同的钥匙进行不同的bfs操作
如果可以到达终点的话即是最终答案
保存钥匙时可以使用压位操作,这样只需要3维数组就可以维护状态(某神犇开12维数组用血淋淋的教训告诉我们还是压位好用)

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
int map[50][50];
int door[50][50][50][50];
bool use[50][50][50];
int x_x[5]={0,0,0,1,-1};
int y_y[5]={0,1,-1,0,0};
struct doubi{
    int x,y,k;
    int g;
};
int n,m,p,k;
queue<doubi> q;
bool can(int x,int y)
{
    if(x>=1&&x<=n&&y>=1&&y<=m){
        return true;
    }
    return false;
}
bool havekey(int k,int num)
{
    return k&(1<<num);
}
void addkey(int &k,int num)
{
    k|=num;
    return ;
}
bool flag=0;
void bfs()
{
    doubi fuckcy;
    fuckcy.x=1,fuckcy.y=1;
    fuckcy.k=0,fuckcy.g=0;
    use[1][1][0]=1;
    q.push(fuckcy);
    while(!q.empty()){
        doubi facy=q.front();
        q.pop();
        int x=facy.x,y=facy.y;
        if(x==n&&y==m){
            cout<<facy.g<<endl;
            flag=1;
            return;
        }
        for(int i=1;i<=4;i++){
            int X=x+x_x[i];
            int Y=y+y_y[i];
            doubi nxt=facy;
            nxt.x=X,nxt.y=Y;
            if(can(X,Y)&&!use[X][Y][facy.k]){
                if(door[x][y][X][Y]==214748364) continue;
                if(door[x][y][X][Y]){
                    if(havekey(nxt.k,door[x][y][X][Y])){
                        nxt.g=facy.g+1;
                        if(map[X][Y])
                        addkey(nxt.k,map[X][Y]);
                        use[X][Y][nxt.k]=1;
                        q.push(nxt);
                    }
                    else continue;
                }
                else{
                    nxt.g=facy.g+1;
                    if(map[X][Y])
                    addkey(nxt.k,map[X][Y]);
                    use[X][Y][nxt.k]=1;
                    q.push(nxt);
                }
            }
        }
    }
}
int main()
{
    cin>>n>>m>>p;
    cin>>k;
    for(int i=1;i<=k;i++){
        int x1,y1,x2,y2,v;
        scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&v);
        if(v==0){
            v=214748364;
        }
        door[x1][y1][x2][y2]=v;
        door[x2][y2][x1][y1]=v;
    }
    int s;
    cin>>s;
    for(int i=1;i<=s;i++){
        int x,y,q;
        scanf("%d%d%d",&x,&y,&q);
        map[x][y]|=1<<q;
    }
    bfs();
    if(!flag){
        cout<<"-1"<<endl;
    }
    return 0;
}

顺带一提codevs拯救大兵瑞恩其中一个点的数据是错的
要想过的话还是打个表比较好= =

最后

以上就是含糊日记本为你收集整理的codevs 1911孤岛营救问题/2219拯救大兵瑞恩的全部内容,希望文章能够帮你解决codevs 1911孤岛营救问题/2219拯救大兵瑞恩所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(62)

评论列表共有 0 条评论

立即
投稿
返回
顶部