第四周
第一题
题目1
有一个n*m迷宫,有T处障碍。通过上下左右四种移动方式,有多少中从起点到终点的方案?
思路1
典型的深搜题。
从起点开始,判断四个方向是否已经经过或是障碍,若都不是就移动到下一格;若没有能走的格就回溯。如此反复,就能得到前往终点的方案。
代码1
#include<iostream>
using namespace std;
//n、m、t、起始点x坐标、起始点y坐标、答案
int n, m, t, sx, sy, fx, fy, ans = 0;
//迷宫、是否访问
bool maze[6][6] = {false}, vis[6][6] = {false};
//向四个方向移动的位移
int xoffset[] = {-1, 0, 1, 0}, yoffset[] = {0, 1, 0, -1};
//深搜
void dfs(int x, int y)
{
//到了终点
if (x == fx && y == fy)
{
//记录答案
ans++;
//回溯
return;
}
//四个方向
for (int i = 0; i < 4; i++)
{
//下一个点的坐标
int nextx = x + xoffset[i];
int nexty = y + yoffset[i];
//保证下一个点不在迷宫外、且不是障碍、没有访问过
if (nextx >= 1 && nexty >= 1 && nextx <= n && nexty <= m && !maze[nextx][nexty] && !vis[nextx][nexty])
{
//记录已访问
vis[nextx][nexty] = true;
//下一次搜索
dfs(nextx, nexty);
//恢复
vis[nextx][nexty] = false;
}
}
}
int main()
{
cin >> n >> m >> t >> sx >> sy >> fx >> fy;
for (int i = 0; i < t; i++)
{
int x, y;
cin >> x >> y;
maze[x][y] = true;
}
//设置起始点已访问
vis[sx][sy] = true;
//开始深搜
dfs(sx, sy);
cout << ans << endl;
return 0;
}
第二题
题目2
m*n的棋盘,再(x, y)上有一个马,问这个马走到棋盘其他地方需要走的步数
思路2
典型的广搜题。
用一个队列存储待搜索的点。以原点为起点,将其放入队列。从队列取出一个点,将马从这个点能到达的点放入队列,并记录到达这个点需要的步数。反复执行直到队列为空,则搜索结束。
代码2
#include<iostream>
#include<iomanip>
#include<queue>
#include<string.h>
using namespace std;
//是否访问
bool vis[401][401];
int n, m;
//马走一步对应的x和y的位移
int xoffset[] = {1, -1, 2, -2, 1, -1, 2, -2}, yoffset[] = {2, -2, -1, 1, -2, 2, 1, -1};
//答案
int ans [401][401];
//用来存放点的坐标和步数,便于放入队列
struct point
{
int x;
int y;
int step;
};
//队列
queue<point> q;
//生成点的函数
inline point newPoint(int x, int y, int step)
{
point p;
p.step = step;
p.x = x;
p.y = y;
return p;
}
int main()
{
int sx, sy;
cin >> n >> m >> sx >> sy;
//把答案的默认值全设置为-1
memset(ans, -1, sizeof(ans));
//左对齐
cout << setiosflags(ios::left);
//把起点放入队列
q.push(newPoint(sx, sy, 0));
//起点已经过
vis[sx][sy] = true;
//广搜 队列不为空是反复执行
while (!q.empty())
{
//当前的点的坐标和步数
int x = q.front().x, y = q.front().y, step = q.front().step;
//已搜索,从队列移除
q.pop();
//记录这一格已经经过多少步数
ans[x][y] = step;
//寻找下一点
for (int i = 0; i < 8; i++)
{
//下一点的坐标
int nextx = x + xoffset[i];
int nexty = y + yoffset[i];
//下一点不能在地图外、且未被访问
if (nextx >= 1 && nextx <= n && nexty >= 1 && nexty <= m && !vis[nextx][nexty])
{
//把符合的点放入队列待搜索
q.push(newPoint(nextx, nexty, step + 1));
//已访问过的点
vis[nextx][nexty] = true;
}
}
}
//输出
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cout << setw(5) << ans[i][j];
}
cout << endl;
}
return 0;
}