题解 SP12323 【NAKANJ - Minimum Knight moves !!!】
本题dfs&bfs做法
前面只有一位大佬写了双向bfs做法,蒟蒻的我在这里提供两种做法(常规bfs&dfs)
题意
给定T组起点,终点和坐标偏移量,求最少需要多少步从起点走到到终点
方法:
很容易看出来,这道题要使用搜索,bfs和dfs均可,这里提供这两种方法
bfs思路:
从起点开始一层一层搜索,第一次搜到终点就得到了最优解,直接返回+输出
dfs思路:
从起点开始重复执行八个方向的搜索,搜到终点就更新答案。但是,这样很明显会TLE,所以我设置了阈值,阈值设成8就可以过全靠数据弱
Code:
#include <iostream>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
char s1, s2, e1, e2;
int N, sx, sy, ex, ey, cnt[110][110] = { 0 }, dx[10] = { 0,1,2,2,1,-1,-2,-2,-1,0 }, dy[10] = { 0,2,1,-1,-2,-2,-1,1,2,0 }, minn;
bool vis[110][110] = { false };
void dfs(int x, int y, int stp)//dfs
{
if (x < 1 || y < 1 || x>8 || y>8 || stp > minn) return;//越界或者当前已经大于最优解,返回
if (x == ex && y == ey) minn = min(minn, stp);//到达终点,更新答案
else
for (int i = 1; i <= 8; i++)
dfs(x + dx[i], y + dy[i], stp + 1);//继续深搜
}
int bfs()//bfs
{
queue<pair<int, int> >Q;//存点用的队列
Q.push(make_pair(sx, sy));//压入起点
vis[sx][sy] = true, cnt[sx][sy] = 0;//标记起点,标记为走过,步数为0
while (!Q.empty())//循环直到队空
{
int nowx = Q.front().first, nowy = Q.front().second;//取队头
if (nowx == ex && nowy == ey) return cnt[nowx][nowy];//到达终点,返回
for (int i = 1; i <= 8; i++)
{
int newx = nowx + dx[i], newy = nowy + dy[i];//扩展新点
if (newx >= 1 && newy >= 1 && newx <= 8 && newy <= 8 && !vis[newx][newy])
{//如果不越界,没走过
Q.push(make_pair(newx, newy));//压入新点
vis[newx][newy] = true, cnt[newx][newy] = cnt[nowx][nowy] + 1;//标记新点
}
}
Q.pop();//弹队头
}
return -1;//到不了
}
int main()
{
cin >> N;//N组数据
while (N--)
{
memset(cnt, 0, sizeof(cnt));
memset(vis, false, sizeof(vis));//初始化
cin >> s1 >> s2 >> e1 >> e2;
sx = s1 - 96, sy = s2 - 48, ex = e1 - 96, ey = e2 - 48;//利用ASCLL码得到起点,终点坐标
/*minn = 8;//dfs把阈值设成8就能过
dfs(sx, sy, 0);
cout << minn << endl;*/
cout << bfs() << endl;
}
return 0;
}
经过我多次实验,dfs阈值最少可以是6
数据:
bfs:20ms / 4.70MB / 1.36KB C++
dfs:
阈值8:740ms / 4.60MB / 1.36KB C++
阈值6:380ms / 4.50MB / 1.36KB C++
两种较简单的方法解析,求管理大大给过