【队列/BFS/DFS】问题 B: DFS or BFS?

3 篇文章 0 订阅
3 篇文章 0 订阅
题目描述

说好了,题目不黑人。

给你一个8*8的矩阵,你的初始位置是左下角方格(用'U’表示),你的目标位置是右上角的方格(用'A'表示),其余的62个方格,如果是'.',表示这个方格为空,如果是'S',表示这个方格有一块大石头。好了现在你开始从左下角出发,每次可以往上,下,左,右,左上,右上,左下,右下移动一个方格,或者你可以原地不动,一共九个动作方式,在你做完一个动作后,所有的大石头会往下掉一个方格(如果一个大石头的位置是(x,y),那下一秒是(x+1,y),不过如果它已经在最下面的一排了,那它就会掉出矩阵,不再出现),请注意,任一时刻,你不能和某一个大石头处在同一个方格,否则石头会把你XX掉。

现在的问题就是:你能从左下角安全抵达右上角么? 如果能,输出“Yes”,反之,“No”。

输入

T->测试数据组数(T)。

对于每组数据,输入一个8*8的矩阵,其后有一空行。描述如上。

输出

对于第i组数据,请输出

Case #i: s(s是一个字符串,如果可以到达,则s为“Yes”,反之“No”)

样例输入 复制
2
.......A
........
........
........
........
........
........
U.......

.......A
........
........
........
........
.S......
S.......
US......
样例输出 复制
Case #1: Yes
Case #2: No
分析:
  1. 利用BFS的思想,先设置一个队列,把起始位置放入,然后不断寻找周围可以走的位置,即不超过地图、不是“S”以及头顶不是“S”的位置,将这些位置放入队列中,当作是第二步可以走到“点”,当第一步所在的“点”全部访问完,更新地图到第二步时的样子,直到无路可走或者到达目的地。

  1. 利用DFS的思想,把步数达到8和找到终点站作为“死胡同”,把选择现在点可以走的位置作为“岔道口”,每次进入“岔道口”带入位置、步数以及新的地图信息。

要点:
  1. BFS
  • 需要记录队列中的点处于第几步,只有当该步的点全部访问完才可以更新地图;

  • 访问到第8步时,说明“S”已经消失,那么之后必定可以到达目的地,因此可以直接表示到达,可以加快大量的时间;

  • 由于使用的是队列,可以把访问顶点时对这个顶点是否可以继续访问放在入队列时预判断,这样可以免去大量同类节点塞入队列导致消耗大量空间。

  1. DFS
  • 可以将对于该位置是否合法的判断放在DFS前面作为“死胡同”,也可以放在“岔路口”后面作为剪枝

  • 由于每次进行进入递归时都要带入新的地图信息,若是直接重新生成char数组,会消耗大量空间,因此用newi、newj、step的信息表示“S”的位置来替代

BFS:
#include <iostream>
#include <queue>

using namespace std;

int ki[9] = {0, -1, -1, -1, 0, 1, 1, 1, 0};
int kj[9] = {-1, -1, 0, 1, 1, 1, 0, -1, 0};
char M[8][8];
struct node{
    int i, j, step;
};

bool Judge(int i, int j){
    if(i >= 0 && i < 8 && j >= 0 && j < 8) return true;
    else return false;
}
void updataM(void){
    for(int i = 7; i >= 0; i--){
        for(int j = 0; j < 8; j++){
            if(M[i][j] == 'S'){
                M[i][j] = '.';
                if(i != 7){
                    M[i + 1][j] = 'S';
                }
            }
        }
    }
}
bool BFS(void){
    queue<node> q;
    node n;
    n.i = 7, n.j = 0, n.step = 0;
    q.push(n);
    int prestep = 0;

    while(!q.empty()){
        n = q.front();
        q.pop();

        if(n.step > prestep){
            prestep = n.step;
            updataM();
        }

        for(int k = 0; k < 9; k++){
            node temp;
            temp.i = n.i + ki[k];
            temp.j = n.j + kj[k];
            temp.step = n.step + 1;

            if(M[temp.i][temp.j] == 'A' || temp.step >= 8){
                return true;
            }
            if(Judge(temp.i, temp.j) && M[temp.i][temp.j] != 'S' && (temp.i == 0 || M[temp.i - 1][temp.j] != 'S')){
                q.push(temp);
            }
        }
    }
    return false;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int T;
    cin >> T;
    for(int z = 1; z <= T; z++){
        for(int i = 0; i < 8; i++){
            for(int j = 0; j < 8; j++){
                cin >> M[i][j];
            }
        }

        if(BFS()){
            cout << "Case #"<< z <<": Yes\n";
        }else{
            cout << "Case #"<< z <<": No\n";
        }

    }
    return 0;
}
DFS:
#include <iostream>

using namespace std;

int ki[9] = {0, -1, -1, -1, 0, 1, 1, 1, 0};
int kj[9] = {-1, -1, 0, 1, 1, 1, 0, -1, 0};
bool flag;
char M[8][8];

bool Judge(int i, int j){
    if(i >= 0 && i < 8 && j >= 0 && j < 8) return true;
    else return false;
}

void DFS(int step, int nowi, int nowj){
    if(step == 8 || M[nowi][nowj] == 'A'){
        flag = true;
        return;
    }

    for(int k = 0; k < 9; k++){
        int newi = nowi + ki[k];
        int newj = nowj + kj[k];
        if(Judge(newi, newj) && M[newi - step][newj] != 'S' && (newi - step == 0 || M[newi - step - 1][newj] != 'S')){
            DFS(step + 1, newi, newj);
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int T;
    cin >> T;
    for(int z = 1; z <= T; z++){
        for(int i = 0; i < 8; i++){
            for(int j = 0; j < 8; j++){
                cin >> M[i][j];
            }
        }

        flag = false;
        DFS(M[8][8], 7, 0);
        if(flag){
            cout << "Case #"<< z <<": Yes\n";
        }else{
            cout << "Case #"<< z <<": No\n";
        }

    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值