poj2243 Knight Moves 骑士游历问题的纯数学方法!!!

http://poj.org/problem?id=2243

 

下面稍微翻译一下:

 

描述:给你一个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枚举
        {
            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;
}


 

 

 

阅读更多

Knight Moves 骑士的移动问题

10-15

DescriptionnA friend of you is doing research on the Traveling Knight Problem (TKP) where you are to find the shortest closed tour of knight moves that visits each square of a given set of n squares on a chessboard exactly once. He thinks that the most difficult part of the problem is determining the smallest number of knight moves between two given squares and that, once you have accomplished this, finding the tour would be easy.nOf course you know that it is vice versa. So you offer him to write a program that solves the "difficult" part. nnYour job is to write a program that takes two squares a and b as input and then determines the number of knight moves on a shortest route from a to b. n nnInputnThe input file will contain one or more test cases. Each test case consists of one line containing two squares separated by one space. A square is a string consisting of a letter (a-h) representing the column and a digit (1-8) representing the row on the chessboard. n nnOutputnFor each test case, print one line saying "To get from xx to yy takes n knight moves.". n nnSample Inputne2 e4na1 b2nb2 c3na1 h8na1 h7nh8 a1nb1 c3nf6 f6n nnSample OutputnTo get from e2 to e4 takes 2 knight moves.nTo get from a1 to b2 takes 4 knight moves.nTo get from b2 to c3 takes 2 knight moves.nTo get from a1 to h8 takes 6 knight moves.nTo get from a1 to h7 takes 5 knight moves.nTo get from h8 to a1 takes 6 knight moves.nTo get from b1 to c3 takes 1 knight moves.nTo get from f6 to f6 takes 0 knight moves.

没有更多推荐了,返回首页