题目链接:http://codeforces.com/problemset/problem/370/A
题目意思:根据rook(每次可以移动垂直或水平的任意步数(>=1)),bishop(每次可以移动对角线上的任意步数(>=1))和king(每次垂直、水平或对角线的一步(=1))的走法,给出起始位置和结束位置。求出这三种棋子分别从起始位置走到最终位置的最少步数。
rook bishop king
首先,先解释下面所说的直线和斜线。
直线:是坐标轴上与x轴平行或与y轴平行的情况的直线。
斜线:图中bishop能走的斜线(能走到坐标点的格子),不是一般的那种斜线(可能走的过程中走不到整数的格子的)
rook是最容易的,如果起始位置和最终位置在同一直线,那么只需要一步即可,否则是两步。
比较麻烦的是bishop,一开始很天真地以为,如果不是斜线的那种情况,bishop就无法到达最终位置。其实处于同一直线也是可以的。如果是(3,1)到(5,1),可以通过(4,2)这个桥梁,到达终点。还有,一般斜线的情况,例如(3,1)到(4,6),可以经过(6,4)。
还是以(3,1)到(4,6)这个例子来说明我的解决办法
考虑到棋盘的特殊性,分别以起点和终点画一条斜线(假设对应为k1和k2),两条斜线必须满足斜率是不同的,满足k1 * k2 = -1),求出两条斜线的交点,判断是否为整数。(注意,即使这个交点超出棋盘范围之外也没有所谓,因为它可以通过另外一个对称点(以黄色标记)来到达目的地)。可能大家会觉得求出交点很麻烦,但是其实也不是很难。由于已经知道斜线上的斜率和交点,那么方程就确定了)
K1 = -1, 方程为: y = -x + 4 (y1 = k1*x1 + b1)
K2 = 1, 方程为: y = x + 2 (y2 = k2*x2 + b2)
联立方程 y = (4 + 2)/ 2 = 2
求出的y是整数,说明交点在格子上,其实得出的交点是什么不重要,关键是判断是否为整数,是则bishop的步数为2,否则不可达,为0。抽象出来,b1 = x1 + y1,b2 = y2 - x2,交点y = (b1+b2)/2。
至此,bishop解决了,还有最后的king,这里不详细说明,不过本人觉得也是要考虑清楚的。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <algorithm> 5 #include <cmath> 6 7 int main() 8 { 9 int r1, c1, r2, c2, t1, t2, flag1, flag2; 10 while (scanf("%d%d%d%d", &r1, &c1, &r2, &c2) != EOF) 11 { 12 // rook 13 flag2 = 0; 14 if ((r1 == r2 && c1 != c2) || (c1 == c2 && r1 != r2)) 15 { 16 flag2 = 1; 17 printf("1 "); 18 } 19 else 20 printf("2 "); 21 // bishop 22 flag1 = 0; 23 if (abs(r1-r2) == abs(c1-c2)) 24 { 25 printf("1 "); 26 flag1 = 1; 27 } 28 else 29 { 30 t1 = r1 + c1; 31 if (r2 > c2) 32 t2 = r2 - c2; 33 else 34 t2 = c2 - r2; 35 if ((t1 + t2) % 2 == 0) 36 printf("2 "); 37 else 38 printf("0 "); 39 } 40 // king 41 if (flag2) //一条直线 42 printf("%d ", abs(r1-r2) + abs(c1-c2)); 43 else if (flag1) //一条斜线 44 printf("%d ", abs(r1-r2)); 45 else if (abs(r1-r2) < abs(c1-c2)) 46 printf("%d ", abs(c1-c2)); 47 else 48 printf("%d ", abs(r1-r2)); 49 } 50 return 0; 51 }