经典算法knight moves中有一些不明白

ssc317 2013-03-31 06:28:29
在网上搜了下经典的knight moves的算法,有一些不懂得地方希望大神解惑!
下面的是网上搜来的答案,已经懂得的网友可以直接略过!
我有两个疑惑!
1.在8*8的网格中对b枚举的时候,下面写到-n/2<=b<=n/2 和 for (b=-4;b<=4;b++) ,
但实际情况是由于该点占了一个,所以它最多只能向上下左右一个方向移动7个,所以对b枚举的时候不是应该for (b=-3;b<=3;b++)更好吗

2.在已经假设了b并且由b得到m的情况下,对a枚举的时候,下面写到
for (a=m-6;a<=m+6;a+=3) //对a枚举

为什么a要等于m-6,为什么a<=m+6?希望网友解释下
因为这个算法很经典,所以应该难不倒各位大神!





描述:给你一个8*8的棋盘,骑士的开始位置,结束位置,让你求得骑士从开始位置开始揍到结束位置需要最小的步数是多少?(注意,骑士走日字)
输入:输入包含多组数据,每一行都是一组开始位置和结束位置,位置由两个字符组成,一个是小写字母(a-h),一个是数字(1-8),起始位置结束位置由一个空格隔开.
输出:输出从起始位置到结束位置,骑士所要走过的最小的步数.按照样例的格式来。
输入样例:
e2 e4
a1 b2
b2 c3
a1 h8
a1 h7
h8 a1
b1 c3
f6 f6
输出样例:
To get from e2 to e4 takes 2 knight moves.
To get from a1 to b2 takes 4 knight moves.
To get from b2 to c3 takes 2 knight moves.
To get from a1 to h8 takes 6 knight moves.
To get from a1 to h7 takes 5 knight moves.
To get from h8 to a1 takes 6 knight moves.
To get from b1 to c3 takes 1 knight moves.
To get from f6 to f6 takes 0 knight moves.
-------------------------------------------------------------------------------------------------------------
一般网上见到的都是dp或者bfs方法。。
但是,对于n稍微大一点,比如80*80,100*100的方格,就很麻烦了。
今天中午 ,我终于想出来了一个数学方法。。
是这样的:
首先,对于两个点,只用考虑其横纵坐标的差值。比如a3,a4,横坐标差值为0,纵坐标差值为1
现在设横纵坐标的差值分别是x,y
由于马只能有8种方法,实际上只会出现4种(举个例子,本来方向向量有(1,2),(2,1),(1,-2),(2,-1),(-1,2),(-2,1),(-1,-2),(-2,-1),但是如果要最小的次数,就不可能同时出现(1,2)和(-1,-2),依次类推)
所以,我们设方向向量为(1,2),(2,1),(2,-1),(1,-2)的分别有a,b,c,d次,其中a,b,c,d可以为负数,a为负数代表方向向量为(-1,-2)
于是,可以列两个方程:
a+2b+2c+d=x
2a+b-c-2d=y
我们要求的是|a|+|b|+|c|+|d|的最小值
首先把a,b,看做常量,解得
c=(-4a-5b+2x+y)/3
d=(5a+4b-x-2y)/3
那么有a+2b和2x+y模3同余
现在2x+y已知,对于b进行枚举,由于-n/2<=b<=n/2,进行枚举,对每个知道a模3是多少,进而再对可能的a进行枚举,从而解出c,d,进而求出总步数。
但是,特别要注意一点,就是角落的问题。
比如a1,b2按上面方法算的是2,实际是4.
经过计算知,对于8*8的只有4种情况:a1 b2;a8 b7;g2 h1;g7 h8;
对这四种情况单独拿出来说就好了。。
以上就是求解的数学方法。下面贴代码,对于原来的8*8题目的。
在poj2243上AC了,228K,32MS。
n*n的稍作修改即可。
--------------------------------

#include <iostream>
#include <string>
using namespace std;

int f(int a) //就是abs(a),绝对值
{
if (a<0)
return 0-a;
return a;
}

int main()
{
string s1,s2;
int a,b,c,d,x,y,s,m;
while (cin >> s1 >> s2)
{
if ((s1=="a1" && s2=="b2") || (s1=="b2" && s2=="a1") || (s1=="g2" && s2=="h1") || (s1=="h1" && s2=="g2"))
{
cout << "To get from " << s1 << " to " << s2 << " takes 4 knight moves." << endl;
continue;
}
if ((s1=="a8" && s2=="b7") || (s1=="b7" && s2=="a8") || (s1=="g7" && s2=="h8") || (s1=="h8" && s2=="g7"))
{
cout << "To get from " << s1 << " to " << s2 << " takes 4 knight moves." << endl;
continue;
}
x=s2[0]-s1[0]; //横坐标差值
s=9999;
y=s2[1]-s1[1]; //纵坐标差值
for (b=-4;b<=4;b++) //对b枚举for (b=-3;b<=3;b++)
{
m=y+2*x-2*b+30; //a模3的余数
m%=3;
for (a=m-6;a<=m+6;a+=3) //对a枚举
{
c=(2*x+y-4*a-5*b)/3; //求出c和d
d=(5*a+4*b-x-2*y)/3;
if (s>f(a)+f(b)+f(c)+f(d))
s=f(a)+f(b)+f(c)+f(d); //判断是否是最小的
}
}
cout << "To get from " << s1 << " to " << s2 << " takes " << s << " knight moves." << endl;
}
return 0;
}
...全文
345 1 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
ZJU_Main 主页 下一页 ZJU 题型分类 文演整理版 2008-3-23 数论: 1007 Numerical Summation of a Series 简单题,还是蛮有意思的 1045 HangOver 简单题 1049 I Think I Need a Houseboat 简单题 1028 Flip and Shift 简单题,可以DP/BFS/……,但是实际上有数学方法可直接判断出来 1026 Modular multiplication of polynomials 简单题,有比较简单的好算法 1307 Packets 简单题,不过也蛮经典的…… 1312 Prime Cuts 简单题 1334 Basically Speaking 简单题 1337 Pi 简单题 1342 Word Index 简单题 1349 Four Quarters 简单题 1350 The Drunk Jailer 简单题 1352 Number Base Conversion 简单题 1353 Unimodal Palindromic Decompositions 规模不大,所以是简单题…… 1354 Extended Lights Out 简单题 1362 Game Prediction 简单题 1365 Mileage Bank 简单题 1382 A Simple Task 简单题 1383 Binary Numbers 简单题 1403 Safecracker 简单题 1408 The Fun Number System 简单题 1486 Color the Tree 简单题 1487 Playing Cards 简单题 1489 2^x mod n = 1 简单题,应该有好算法,不过枚举就可以过…… 1503 One Person "The Price is Right" 简单题,POI Eggs的翻版 1512 Water Treatment Plants 简单题,组合计数 1526 Big Number 简单题,不过O(1)和O(n)还是有区别的:) 1529 Enigmatic Travel 简单题,不过个人感觉题目描述很令人费解 1530 Find The Multiple 简单题 1537 Playing with a Calculator 简单题 1577 GCD & LCM 简单题,分区联赛的题…… 1005 Jugs 简单题 1543 Stripies 简单题 1569 Partial Sums 简单题 1062 Trees Made to Order 简单题 1070 Bode Plot 简单题 1073 Round and Round We Go 简单题,142857,我喜欢^_^ 1078 Palindrom Numbers 简单题 1086 Octal Fractions 简单题 1199 Point of Intersection 简单题 1104 Leaps Tall Buildings 简单题 1110

3,882

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 其它技术问题
社区管理员
  • 其它技术问题社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧