T1:# 迷宫
## 题目描述
给定一个 $N \times M$ 方格的迷宫,迷宫里有 $T$ 处障碍,障碍处不可通过。
在迷宫中移动有上下左右四种方式,每次只能移动一个方格。数据保证起点上没有障碍。
给定起点坐标和终点坐标,每个方格最多经过一次,问有多少种从起点坐标到终点坐标的方案。
## 输入格式
第一行为三个正整数 $N,M,T$,分别表示迷宫的长宽和障碍总数。
第二行为四个正整数 $SX,SY,FX,FY$,$SX,SY$ 代表起点坐标,$FX,FY$ 代表终点坐标。
接下来 $T$ 行,每行两个正整数,表示障碍点的坐标。
## 输出格式
输出从起点坐标到终点坐标的方案总数。
## 样例 #1
### 样例输入 #1
```
2 2 1
1 1 2 2
1 2
```
### 样例输出 #1
```
1
```
## 提示
对于 $100\%$ 的数据,$1 \le N,M \le 5$,$1 \le T \le 10$,$1 \le SX,FX \le n$,$1 \le SY,FY \le m$。
DFS(depth first search):深度优先搜索
解决枚举量过于大,
模板:
void dfs(一般是点x,或者层数)
{
if(判断搜索完成)记录答案return;
for枚举这个点走的方式{
if判断这个方式是否合法{
标记这个点
dfs(下一个点)
取消这个点的标记(回溯)
}
}
}
图解:
- :存图
2:标记初始点
3.访问
代码:
#include<bits/stdc++.h>
using namespace std;
int N,M,T,sx,sy,fx,fy,ans;
int x,y,vis[10006][10006];
void dfs(int x,int y){
if(x==fx&&y==fy){
ans++;
return;
}//到达终点答案加加
//向上走
if(y<M&&vis[x][y+1]==0){
vis[x][y+1]=1;
dfs(x,y+1);
vis[x][y+1]=0;
}
//向下走
if(y>1&&vis[x][y-1]==0){
vis[x][y-1]=1;
dfs(x,y-1);
vis[x][y-1]=0;
}
//向左走
if(x>1&&vis[x-1][y]==0)
{
vis[x-1][y]=1;
dfs(x-1,y);
vis[x-1][y]=0;
}
if(x<N&&vis[x+1][y]==0)
{
vis[x+1][y]=1;
dfs(x+1,y);
vis[x+1][y]=0;
}
return;
}
int main()
{
cin>>N>>M>>T>>sx>>sy>>fx>>fy;
vis[sx][sy]=1;
for(int i=1;i<=T;i++){
int a,b;
cin>>a>>b;
vis[a][b]=1;
}
dfs(sx,sy);
cout<<ans;
return 0;
}
T2:马的遍历
## 题目描述
有一个 $n \times m$ 的棋盘,在某个点 $(x, y)$ 上有一个马,要求你计算出马到达棋盘上任意一个点最少要走几步。
## 输入格式
输入只有一行四个整数,分别为 $n, m, x, y$。
## 输出格式
一个 $n \times m$ 的矩阵,代表马到达某个点最少要走几步(不能到达则输出 $-1$)。
## 样例 #1
### 样例输入 #1
3 3 1 1
### 样例输出 #1
0 3 2
3 -1 1
2 1 4
## 提示
### 数据规模与约定
对于全部的测试点,保证 $1 \leq x \leq n \leq 400$,$1 \leq y \leq m \leq 400$。
BFS(Breadth first search):广度优先搜索
优先考虑搜索的深度,解决连通性,最短路问题,通过队列实现
模板:
q.push(初始点)//将初始点压入队列
while(!q.empty())//队列不为空时执行
{
int n=q.front()//将队首的元素取出,并删除
q.pop();
for()枚举下一个状态的所有情况
{
int next=;
if()//如果枚举的这个点合理
{
对它进行相应的操作,并把它压入队列尾
q.push(next);
}
}
}
图解:
思路:
首先分析马走下一步可能的情况,一共八种,用数组分别储存这八组的变化的x,y;
然后:依据题意将未到达的点全部标记为-1
再:进行BFS,同时用一个dot二维数组记录答案
代码
#include<bits/stdc++.h>
using namespace std;
int N,M,sx,sy;
int nx[]={-2,-2,-1,-1,1,1,2,2};
int ny[]={1,-1,2,-2,2,-2,1,-1};
int dot[1006][1006];
queue <pair<int,int> > q;
int main()
{
cin>>N>>M>>sx>>sy;
memset(dot,-1,sizeof(dot));//标记未到达的地方全为-1(好处:不用判断哪个点没有走过 )
dot[sx][sy]=0;//将出发点标记为零
q.push(make_pair(sx,sy));//将出发点压入队列
while(!q.empty()){
int now_x=q.front().first,now_y=q.front().second;//弹出并删除队首的点
q.pop();
for(int i=0;i<8;i++)//搜寻下一能到达的点
{
int next_x=now_x+nx[i],next_y=now_y+ny[i];
if(next_x<=N&&next_x>=1&&next_y<=M&&next_y>=1&&dot[next_x][next_y]==-1)
{
dot[next_x][next_y]=dot[now_x][now_y]+1;//这里不用担心少算了一步(开头将dot标记为-1),因为是从起点(0)开始算的
q.push(make_pair(next_x,next_y));//将能到达的点压入队列
}
}
}
for(int i=1;i<=N;i++)
{
for(int j=1;j<=M;j++)
{
printf("%d ",dot[i][j]);
}
cout<<endl;
}
return 0;
}
补充yhgg教的一个pair容器:
- 头文件:#include <utility>
- 定义:pair<数据类型,数据类型>
- 访问内部元素(仅有两个:p.first,p.second
- 赋值:可以赋值给同类型的pair对象s,s=make_pair(x,y)