POJ2243 Knight Moves

题意:给你一个8*8的棋盘,已知骑士的开始位置、结束位置,让你求得骑士从开始位置走到结束位置所需要的最小步数是多少(骑士走日字)?


输入:输入包括多组数据,每一行都是一组开始位置和结束位置,位置由两个字符组成,一个是小写字母(a-h),一个是数字(1-8),起始位置结束位置由一个空格隔开。


输出:输出从起始位置到结束位置,骑士所要走过的最小的步数.按照样例的格式来。

纯数学方法:

首先,对于两个点,现在设横纵坐标的差值分别为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+2c+d=x , 2a+b-c-2d=y
   所以2x+y = 2(a+2b+2c+d)+(2a+b-c-2d) 
                   = 4a+5b+3c
(2x+y) mod 3 = (4a+5b+3c) mod 3
                          = (a+2b) mod 3
那么有2x+y和a+2b模3同余。
现在2x+y已知,对b进行枚举,对每个知道a模3是多少,进而再对可能的a进行枚举,从而解出c、d,进而求出步数。

但是如果上面所提到的就是你能想到的全部,还是会出错。。
特别需要注意的一点就是角落的问题,比如输入a1、b2按上面的方法算的是2,实际上是4。
对于8*8的棋盘只有四种特殊情况就是:
   a1、b2,  a8、b7,  g2、h1,  g7、h8
对这四种情况单独拿出来就好了。。

举一例:


#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>

using namespace std;

int main()
{
    int a, b, c, d, x, y, m, ans;
    string s1, s2;
    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];
        y = s2[1] - s1[1];
        ans = 10001;
        for(b = -8; b <= 8; b++)  //对b进行枚举
        {
            m = y + 2 * x - 2 * b + 30;
            m %= 3;  //a模3的余数
            for(a = m - 9; a <= m + 9; a += 3)
            {
                c = (2 * x + y - 4 * a - 5 * b) / 3;
                d = (5 * a + 4 * b - x - 2 * y) / 3;
                if(ans > abs(a) + abs(b) + abs(c) + abs(d))
                    ans = abs(a) + abs(b) + abs(c) + abs(d);
            }
        }
        cout << "To get from " << s1 << " to " << s2 << " takes " << ans << " knight moves." << endl;
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值