POJ 1915 Knight Moves

来源:互联网 发布:秦美人天神进阶数据 编辑:程序博客网 时间:2024/06/06 04:44

题目:另外一个类似的题目

Description

Background
Mr Somurolov, fabulous chess-gamer indeed, asserts that no one else but him can move knights from one position to another so fast. Can you beat him? 
The Problem
Your task is to write a program to calculate the minimum number of moves needed for a knight to reach one point from another, so that you have the chance to be faster than Somurolov. 
For people not familiar with chess, the possible knight moves are shown in Figure 1. 


Input

The input begins with the number n of scenarios on a single line by itself. 
Next follow n scenarios. Each scenario consists of three lines containing integer numbers. The first line specifies the length l of a side of the chess board (4 <= l <= 300). The entire board has size l * l. The second and third line contain pair of integers {0, ..., l-1}*{0, ..., l-1} specifying the starting and ending position of the knight on the board. The integers are separated by a single blank. You can assume that the positions are valid positions on the chess board of that scenario.

Output

For each scenario of the input you have to calculate the minimal amount of knight moves which are necessary to move from the starting point to the ending point. If starting point and ending point are equal,distance is zero. The distance must be written on a single line.

Sample Input

380 07 01000 030 50101 11 1

Sample Output

5280

这个题目,我的运行时间比他们都短,我只有47ms。

维度l不超过300可能还不明显,如果维度再大几倍可能就非常明显了。

我的思路是基于我自己对马的一些研究的。

整个求解分为2大部分,第一部分是化简,第二部分是广度优先搜索。

第一部分的核心代码:

cin >> n >> a >> b >> c >> d;int x = (a > c) ? a - c : c - a;int y = (b > d) ? b - d : d - b;int sum = 0;while (x > 5 || y > 5){if (x > y){x -= 2;if (y)y--;else y++;}else{y -= 2;if (x)x--;else x++;}sum++;}

x就是横坐标a和c的差,y就是纵坐标b和d的差。

然后直接开始走马,直到x和y都不超过5(保持x和y必须非负),每走一步sum都加1。

到了这个时候,广度优先搜索可以说是常数级别的时间代价了。

甚至可以用数组保存结果,直接输出。

当然了,考虑到边界的问题,这样做非常麻烦。

所以第二部分还是用了广度优先搜索,因为x和y都不超过5,广度优先搜索非常快。

至于我的思路的正确性,首先给出我思考的时候画的2个图。

2个图都是从0出发,到每个格子的最短步数。


这个图是在6*6的棋盘上面的结果,即0就是在角落。


这个图是在没有边界的棋盘上面的结果,没有角落,没有边界限制。


这2个图仅有的区别是3个格子,我已经标注出来了。


也就是说,对于这样的L型中的格子来说,对于任意维度的棋盘和对于任意的边界位置来说,结果都是一样的。

如果棋盘足够大,而且0在中间的话,4个这样的L型其实是构成了一个保护圈的。

请允许我自定义它为“数据一致性保护圈”。

如果0在边界的话,2个L型和1条边界照样构成保护圈。

如果0在角落的话,1个L型和2条边界也构成保护圈。


那么,保护圈到底有什么用呢?

很明显,要从保护圈外面到0那个点,就必须先到保护圈中的某个点,所以总步数是2个部分分开求的。

而且,并不需要遍历保护圈,求总步数的最小值,直接根据2个点的位置就可以求出来应该选保护圈中的哪个点作为中转点。


请注意,中转点的选择很容易,而且是绝对正确的,但是从中转点到0那个点的最短步数是不能直接用上面的数的。

比如对于3*30的棋盘,上面的图片中的具体数值是没有意义的。

但是仍然可以轻松选出中转点,然后从中转点到0那个点的距离用广度优先搜索求的话非常非常快。


代码:

#include<iostream>#include<queue>using namespace std;bool ok(int c, int d, int n,int**list){if (c < 0 || c >= n)return false;if (d < 0 || d >= n)return false;if (list[c][d] < 0)return true;return false;}int list1[8] = { 1, 1, 2, 2, -1, -1, -2, -2 };int list2[8] = { 2, -2, 1, -1, 2, -2, 1, -1 };int bfs(int a, int b, int x, int y, int n){int **list = new int*[n];for (int i = 0; i < n; i++){list[i] = new int[n];for (int j = 0; j < n; j++)list[i][j] = -1;}list[a][b] = 0;queue <int>q;q.push(a*n + b);int c, d;while (list[x][y]<0){c = q.front()/n;d = q.front() % n;q.pop();for (int i = 0; i < 8;i++)if (ok(c + list1[i], d + list2[i], n, list)){q.push((c + list1[i])* n + d + list2[i]);list[c + list1[i]][d + list2[i]] = list[c][d] + 1;}}return list[x][y];}int main(){int t;cin >> t;int n;int a, b, c, d;while (t--){cin >> n >> a >> b >> c >> d;int x = (a > c) ? a - c : c - a;int y = (b > d) ? b - d : d - b;int sum = 0;while (x > 5 || y > 5){if (x > y){x -= 2;if (y)y--;else y++;}else{y -= 2;if (x)x--;else x++;}sum++;}int xx = a, yy = b;if (xx >= x)xx -= x;else xx += x;if (yy >= y)yy -= y;else yy += y;sum += bfs(a, b, xx, yy, n);cout << sum << endl;}return 0;}

2 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 腹股沟岔气怎么办才能快点好 瑜伽馆不给退卡怎么办 膝盖总是凉凉的怎么办 练阴瑜伽腿麻怎么办 瑜伽垫在地板滑怎么办 艾灸后后背发凉怎么办 床上老是有小蜈蚣怎么办 早晚出去胳膊脚觉得凉怎么办 腿凉感觉冒凉气怎么办 冬天腿被冻夏天发酸发凉怎么办 宿舍一楼虫子多怎么办 有虫子在咬床板怎么办 床板上的虫咬了怎么办 住的房间有臭虫怎么办 租的房子有臭虫怎么办 瑜伽垫放地上脏怎么办 瑜伽垫和地面滑怎么办 练瑜伽时瑜伽垫全是汗水怎么办 车钥匙放洗衣机洗了怎么办 瑜伽垫边上掉渣怎么办 晚上睡地上后背不舒服怎么办 小孩子天天晚上看电视不睡觉怎么办 宝宝天天晚上不睡觉怎么办 老公天天晚上不睡觉怎么办 小孩天天晚上不睡觉怎么办 摸了貔貅的眼睛怎么办 买的爬行垫滑怎么办 买了爬行垫有毒怎么办 xpe爬行垫破了怎么办 做瑜伽时平衡不好怎么办 鼻翼两侧发红长痘怎么办 孕后期睡觉背疼怎么办 练了瑜伽后腰痛怎么办 尿路口长疮疼痛怎么办 来月经吃了辣的怎么办 泳衣打湿后特别难脱怎么办 脚臭怎么办教你除臭方法 袜子没干就穿了进湿气怎么办 狗喜欢往床上跑怎么办 泰迪在床上睡觉怎么办 泰迪睡觉换地方怎么办