拯救大兵瑞恩——状态压缩+bfs算法

1944 年,特种兵麦克接到国防部的命令,要求立即赶赴太平洋上的一 个孤岛,营救被敌军俘虏的大兵瑞恩。瑞恩被关押在一个迷宫里,迷宫地形
复杂,但是幸好麦克得到了迷宫的地形图。 迷宫的外形是一个长方形,其在南北方向被划分为 N 行,在东西方向被 划分为 M
列,于是整个迷宫被划分为 N×M 个单元。我们用一个有序数对(单 元的行号,单元的列号)来表示单元位置。南北或东西方向相邻的两个单元
之间可以互通,或者存在一扇锁着的门,又或者存在一堵不可逾越的墙。迷 宫中有一些单元存放着钥匙,并且所有的门被分为 P 类,打开同一类的门的
钥匙相同,打开不同类的门的钥匙不同。 大兵瑞恩被关押在迷宫的东南角,即(N,M)单元里,并已经昏迷。迷宫
只有一个入口,在西北角,也就是说,麦克可以直接进入(1,1)单元。另外, 麦克从一个单元移动到另一个相邻单元的时间为
1,拿取所在单元的钥匙的 时间以及用钥匙开门的时间忽略不计。 输入: 第一行是三个整数,依次表示 N,M,P
的值;(3≤N,M≤15,1≤P≤10) 第二行是一个整数 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) 输出 对每组数据只输出一个整数 T,表示麦克营救到大兵瑞恩的最短时间
的值,若不存在可行的营救方案则输出-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

这道题目是我们学校的实验题目,有两道实验,一个是超市选址问题,另外一个是这个比较复杂的数据结构迷宫寻路问题。由于之前已经做到了bfs算法迷宫寻路问题,因此想挑战下这个比较拿手的迷宫寻路问题,从下午1点多一直编到晚上7点多,不过所幸还是把它给编了出来。

样例输入格式化:
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

图解:
在这里插入图片描述
通过图解,位置,门,墙的关系一目了然。
而题中的数据仅仅给出了各个位置之间的门、墙情况。
因此,需另生成一个pass数组,数组的行分量记录该位置在各个方向的门、墙情况。
例如:
位置 东 南 西 北
(0,0) pass pass pass pass
(0,1) door2 wall pass pass

迷宫越界的情况在bfs函数中考虑。
信息表的生成代码

    int information[20][5];
    int m,n,p;
    cin>>m>>n>>p;  //record row
    int k;
    cin>>k;
    for(int i = 0; i < k ; i ++)
        for(int j = 0; j < 5 ; j++)
    cin>>information[i][j];
    int s;
    cin>>s;
    int key[5][3]={
   0};
    for(int i = 0; i < s ; i ++)
        for(int j = 0 ; j < 3 ; j ++)
               cin>>key[i][j];
    int pass[100][4]={
   0}; //0表示可以通过,1表示不可通过
    for(int i = 0; i< k ; i ++){
   
        int p=information[i][4];
        if(!p)
            p=-1;
        if(information[i][3]-information[i][1]){
   
            pass[(information[i][0]-1)*n+information[i][1]-1][0]=p;
            pass[(information[i][2]-1)*n+information[i][3]-1][2]=p;
        }
        else{
   
            pass[(information[i][0]-1)*n+information[i][1]-1][1]=p;
            pass[(information[i][2]-1)*n+information[i][3]-1][3]=p;
        }
    }

下直接给出bfs代码(此时我的脑袋已经迷迷糊糊了,下次再出个bfs迷宫寻路的讲解)

struct location{
   
    int x;//横坐标
    int y;//纵坐标
    int footstep;//步数
};
int bfs(int pass[100][4],int *key,int m0,int n0,int m1,int n1,int m,int n,int &flag){
   
    flag=0;
    queue<location> way;
    int vist[100][100]={
   0};//标记是否被访问过
    location now_lc;
    now_lc.x=m0;
    now_lc.y=n0;
    vist[m0][n0]=1;
    now_lc.footstep=0;
    way.push(now_lc);
    while(!way.empty()){
   
        location old_lc=way.front();
        way.pop();
        if((!pass[old_lc.x*n+old_lc.y][0]||(pass[old_lc.x*n+old_lc.y][0]>0&&key[pass[old_lc.x*n+old_lc.y][0]]))&&!vist[old_lc.x][old_lc.y+1]&&old_lc.x<m&&old_lc.y+1<n){
   
            now_lc
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值