Problem B: DFS or BFS?
题目
Description
说好了,题目不黑人。
给你一个8*8的矩阵,你的初始位置是左下角方格(用’U’表示),你的目标位置是右上角的方格(用’A’表示),其余的62个方格,如果是’.’,表示这个方格为空,如果是’S’,表示这个方格有一块大石头。好了现在你开始从左下角出发,每次可以往上,下,左,右,左上,右上,左下,右下移动一个方格,或者你可以原地不动,一共九个动作方式,在你做完一个动作后,所有的大石头会往下掉一个方格(如果一个大石头的位置是(x,y),那下一秒是(x+1,y),不过如果它已经在最下面的一排了,那它就会掉出矩阵,不再出现),请注意,任一时刻,你不能和某一个大石头处在同一个方格,否则石头会把你XX掉。
现在的问题就是:你能从左下角安全抵达右上角么? 如果能,输出“Yes”,反之,“No”。
Input
T->测试数据组数(T)。
对于每组数据,输入一个8*8的矩阵,其后有一空行。描述如上。
Output
对于第i组数据,请输出
Case #i: s(s是一个字符串,如果可以到达,则s为“Yes”,反之“No”)
Sample Input Copy
2
.......A
........
........
........
........
........
........
U.......
.......A
........
........
........
........
.S......
S.......
US......
Sample Output Copy
Case #1: Yes
Case #2: No
思路
- 本题使用bfs,需要一个队列来push和pop点从而走迷宫,详情请见bfs相关知识
- 注意使用states(set)来判断是否该坐标和当时的bottom的值是否曾经出现过
- 因为bfs是不断push和pop来保存状态的
- 所以可能造成到达某一层的A点和B点继续运动后会同时到达C点,状况重复
- 与过去的bfs不同的是,本题有每动一次,石头集体下落一格的特殊要求
- 如果遍历整个map,会造成非常大的时间复杂度
- 所以比起修改整体的地图,更好的选择是切换视角
- 也就是top[2]所做的工作,同时top[2]可以保证点向上运动的趋势,从而快速达到最终点
- 当达到最上面一行时,一定可以到达终点(只要向左一直走就好),直接return。
代码
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <set>
#include <queue>
using namespace std;
char map[8][8];
set<vector<int>> states;//用set判断人物移动后,坐标和bottom的值是否曾经出现过
int flag;
struct point{
int x;
int y;
int step;
};
bool check(int x,int y,int bottom){
//注意判断其上方是否是一个石头
if(x>=0&&x<=bottom&&y>=0&&y<8&&map[x][y]!='S'&&map[x-1][y]!='S')
return true;
return false;
}
void bfs(){
states.clear();
states.insert({
7,0,7});//插入起始点
queue<vector<int>> Q;//bfs队列
Q.push({
7,0,7});//插入起始点
while(!Q.empty()){
//队列为空,bfs结束
vector<int> top=Q.front();
if(top[2]==0||top[0]==0){
//代表到达最上面一行以上,则安全
flag=true;
return;
}
Q.pop();//弹出,开始处理
for(int i=-1;i<=1;i++){
for(int j=-1;j<=1;j++){
if(check(top[0]+i,top[1]+j,top[2])&&!states.count({
top[0]+i-1,top[1]+j,top[2]-1})){
states.insert({
top[0]+i-1,top[1]+j,top[2]-1});//插入新点
Q.push({
top[0]+i-1,top[1]+j,top[2]-1});
}
}
}
}
}
int main(){
int n=0;
while(scanf("%d",&n)!=EOF){
for(int k=1;k<=n;k++){
flag=false;
string input;
getline(cin,input);
for(int i=0;i<8;i++){
getline(cin,input);
for(int j=0;j<8;j++){
map[i][j]=input[j];
}
}
bfs();
printf("Case #%d: %s\n", k, flag ? "Yes" : "No");
}
}
return 0;