搜索
迷宫
题目描述
给定一个 N × M N \times M N×M 方格的迷宫,迷宫里有 T T T 处障碍,障碍处不可通过。
在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。
给定起点坐标和终点坐标,每个方格最多经过一次,问有多少种从起点坐标到终点坐标的方案。
输入格式
第一行为三个正整数 N , M , T N,M,T N,M,T,分别表示迷宫的长宽和障碍总数。
第二行为四个正整数 S X , S Y , F X , F Y SX,SY,FX,FY SX,SY,FX,FY, S X , S Y SX,SY SX,SY 代表起点坐标, F X , F Y FX,FY FX,FY 代表终点坐标。
接下来 T T T 行,每行两个正整数,表示障碍点的坐标。
输出格式
输出从起点坐标到终点坐标的方案总数。
样例 #1
样例输入 #1
2 2 1
1 1 2 2
1 2
样例输出 #1
1
提示
对于 100 % 100\% 100% 的数据, 1 ≤ N , M ≤ 5 1 \le N,M \le 5 1≤N,M≤5, 1 ≤ T ≤ 10 1 \le T \le 10 1≤T≤10, 1 ≤ S X , F X ≤ n 1 \le SX,FX \le n 1≤SX,FX≤n, 1 ≤ S Y , F Y ≤ m 1 \le SY,FY \le m 1≤SY,FY≤m。
代码
#include<iostream>
using namespace std;
bool maze[6][6]; //迷宫数组
int N,M,T;
int stx, sty, finx, finy; //开始的x和y,终止的x和y
int route = 0; //总共有几条路线
void dfs(int x, int y){
if(x > M || y > N || x < 0 || y < 0 || maze[x][y] == false) //当前的路不可以走
return;
if(x == finx && y == finy){ //走到终点坐标
route++;
return;
}
maze[x][y] = false; //将当前坐标设为已经走过
dfs(x-1,y);
dfs(x,y-1);
dfs(x+1,y);
dfs(x,y+1);
maze[x][y] = true; //返还当前坐标
return;
}
int main(){
cin>>N>>M>>T;
//初始化数组
for(int i = 0; i < 6; ++i)
for(int j = 0; j < 6; ++j)
maze[i][j] = false;
for(int i = 1; i <= M; ++i)
for(int j = 1; j <= N; ++j)
maze[i][j] = true;
cin>>stx>>sty>>finx>>finy;
for(int i = 0; i < T; ++i){
int ox, oy; //障碍的x和y
cin>>ox>>oy;
maze[ox][oy] = false;
}
dfs(stx,sty);
cout<<route<<endl;
system("pause");
return 0;
}
注意点
- 采用深度优先搜索,但是本题中需要对已经访问过的点进行标记,防止走回去。而访问了该点之后也要将该店设为可以访问,否则会形成死路
- 判断当前点是否可以走应该在函数最前面,否则会出现终点为一个障碍而程序判断出来依旧可达的情况
马的遍历
题目描述
有一个 n × m n \times m n×m 的棋盘,在某个点 ( x , y ) (x, y) (x,y) 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。
输入格式
输入只有一行四个整数,分别为 n , m , x , y n, m, x, y n,m,x,y。
输出格式
一个 n × m n \times m n×m 的矩阵,代表马到达某个点最少要走几步(不能到达则输出 − 1 -1 −1)。
样例 #1
样例输入 #1
3 3 1 1
样例输出 #1
0 3 2
3 -1 1
2 1 4
提示
数据规模与约定
对于全部的测试点,保证 1 ≤ x ≤ n ≤ 400 1 \leq x \leq n \leq 400 1≤x≤n≤400, 1 ≤ y ≤ m ≤ 400 1 \leq y \leq m \leq 400 1≤y≤m≤400。
代码
#include<iostream>
#include<queue>
using namespace std;
int step[401][401];
int row, col, stx, sty; //棋盘长宽,马开始位置
typedef struct elem{ //二元组
int x;
int y;
int totalStep;
}elem;
queue<elem*> cur; //list存储二元组
void bfs(){ //广度优先遍历
//初始位置进队
elem *first = new elem;
first->x = stx - 1;
first->y = sty - 1;
first->totalStep = 0;
cur.push(first);
while(!cur.empty()){
elem *temp = cur.front();
cur.pop();
int x = temp->x;
int y = temp->y;
int curStep = temp->totalStep;
//cout<<"x = "<<x<<" y = "<<y<<" curStep = "<<curStep<<endl;
if(x < 0 || y < 0 || x >= row || y >= col || step[x][y] != -1) //越界
continue;
//之前还没来过,将其设为当前步长
step[x][y] = temp->totalStep;
//左上1
elem *leftUp1 = new elem;
leftUp1->x = x - 1;
leftUp1->y = y - 2;
leftUp1->totalStep = curStep + 1;
cur.push(leftUp1);
//左上2
elem *leftUp2 = new elem;
leftUp2->x = x - 2;
leftUp2->y = y - 1;
leftUp2->totalStep = curStep + 1;
cur.push(leftUp2);
//左下1
elem *leftDown1 = new elem;
leftDown1->x = x - 1;
leftDown1->y = y + 2;
leftDown1->totalStep = curStep + 1;
cur.push(leftDown1);
//左下2
elem *leftDown2 = new elem;
leftDown2->x = x - 2;
leftDown2->y = y + 1;
leftDown2->totalStep = curStep + 1;
cur.push(leftDown2);
//右上1
elem *rightUp1 = new elem;
rightUp1->x = x + 1;
rightUp1->y = y - 2;
rightUp1->totalStep = curStep + 1;
cur.push(rightUp1);
//右上2
elem *rightUp2 = new elem;
rightUp2->x = x + 2;
rightUp2->y = y - 1;
rightUp2->totalStep = curStep + 1;
cur.push(rightUp2);
//右下1
elem *rightDown1 = new elem;
rightDown1->x = x + 1;
rightDown1->y = y + 2;
rightDown1->totalStep = curStep + 1;
cur.push(rightDown1);
//右下2
elem *rightDown2 = new elem;
rightDown2->x = x + 2;
rightDown2->y = y + 1;
rightDown2->totalStep = curStep + 1;
cur.push(rightDown2);
}
}
int main(){
for(int i = 0; i < 401; ++i) //初始化数组
for(int j = 0; j < 401; ++j)
step[i][j] = -1;
cin>>row>>col>>stx>>sty;
bfs();
for(int i = 0; i < row; ++i){
for(int j = 0; j < col; ++j){
cout<<step[i][j]<<" ";
}
cout<<endl;
}
system("pause");
return 0;
}
注意点
- 采用广度优先算法bfs
- 由于采用的是bfs,马第一次访问某点的步数即为最短步数,后面若再次访问该点可以直接跳过,不需要再次判断
- 使用二元组elem,其中x,y代表坐标,totalStep代表走到该点需要的步数
typedef struct elem{ //二元组
int x;
int y;
int totalStep;
}elem;
- 马共有八个方向可以移动,每次从队列中弹出一个元素,就要让其周围八个点的坐标全部入队,此八个点的步长为当前弹出元素的步长+1