题目描述:
在国际象棋的棋盘上放置3个骑士的棋子,按照骑士的移动规则移动这3个棋子,使其到达同一个位置,求最少的移动次数。
解答:
本题不难。首先说明一下国际象棋的规则,棋盘由8×8=64个黑白相间的格子组成,棋子放在某一个格子中。采用二维坐标的方式表示棋盘中的每一个格子,其中水平方向从左到右用 A-H 这8个英文字母表示,竖直方向从下到上用 1-8 这8个数字表示,如下图:
国际向其中的棋子“骑士”的走法和中国象棋中的马的走法类似,沿着一个2×3的矩形区域的对角线移动,如下图:
因此在不考虑棋盘的范围的情况下,假设棋盘的范围无限,那么每一个马都有8个不同的位置使得该棋子移动1次就可到达:
后续的步骤可分为两种方法进行:
·方法一:
将棋盘中的每一个位置和其他8个可以直接到达的位置用边连接,同时设定边的长度为1,那么分别将3个棋子的初始位置作为起点,利用dijkstra算法就可以计算出该棋子到达每个位置时需要移动的最小步数。将3个棋子的情况分别计算后,枚举棋盘中的每一个位置,找到使得3个棋子的移动到该位置的步数的总和的最小值,就是本题的答案。
·方法二:
也可以同时对于3个棋子的位置来分析。由于每个棋子的横纵坐标都只有8种不同的可能,因此,3个棋子的位置就可以用一个6位的8进制数来表示,用不同的数字表示不同的“状态点”,由于每一个棋子都有8个位置可以移动一次到达,因此每个“状态点”都有3×8=24个不同的“状态点”,可以通过移动1此3个棋子中的某一个棋子来达到与当前状态点的转换,因此,此时抽象出的“图”中的每个“点”最多有24个“点”与其邻接。以初始位置的状态作为起点,利用dijkstra算法找到和其他所有状态的最短距离,然后遍历那些3个棋子在同一个位置的状态,找到最短的距离即可。
下面的代码采用的是方法一。
输入输出格式:
输入:
第1行:1个正整数t,表示数据组数,2≤t≤10;第2..t+1行:用空格隔开的3个坐标, 每个坐标由2个字符AB组成,A为A-H的大写字母,B为1-8的数字,表示3个棋子的初始位置。
输出:
第1..t行:每行1个数字,第i行表示第i组数据中3个棋子移动到同一格的最小行动步数。
数据范围:
2 ≤ t ≤ 10
程序代码:
/****************************************************/
/* File : Hiho_Week_99 */
/* Author : Zhang Yufei */
/* Date : 2016-05-24 */
/* Description : HihoCoder ACM program. (submit:g++)*/
/****************************************************/
#include<stdio.h>
#include<stdlib.h>
/*
* Define structure to record chess information.
*/
typedef struct node {
int distance;
int tag;
} chess;
/*
* Record the position which is accessable by moving only once from orginal place.
*/
int position[8][2] = {
{-1, 2}, { 1, 2}, { 2, -1}, { 2, 1},
{-1, -2}, { 1, -2}, {-2, -1}, {-2, 1}
};
/*
* Record the map of chess. The element is the mininum steps to move from the
* start position
*/
chess **chess1;
chess **chess2;
chess **chess3;
/*
* This function computes the shortest distance between every position in the map
* and the start position.
* Parameters:
* @x & @y: The start postion.
* @map: The chess map.
* Returns:
* None.
*/
void dijkstra(chess **map, int x, int y) {
map[x][y].distance = 0;
map[x][y].tag = 1;
int set[64][2];
set[0][0] = x;
set[0][1] = y;
int xi, yi, x_n, y_n;
int min_x, min_y;
int min;
min_x = x;
min_y = y;
for(int i = 0; i < 8; i++) {
x_n = min_x + position[i][0];
y_n = min_y + position[i][1];
if(x_n >= 0 && x_n < 8 && y_n >= 0 && y_n < 8) {
if(map[x_n][y_n].tag == 0) {
if(map[x_n][y_n].distance == -1 ||
map[x_n][y_n].distance > map[min_x][min_y].distance + 1) {
map[x_n][y_n].distance = map[min_x][min_y].distance + 1;
}
}
}
}
int count = 1;
while(count < 64) {
min = -1;
for(int i = 0; i < count; i++) {
xi = set[i][0];
yi = set[i][1];
for(int j = 0; j < 8; j++) {
x_n = xi + position[j][0];
y_n = yi + position[j][1];
if(x_n >= 0 && x_n < 8 && y_n >= 0 && y_n < 8) {
if(map[x_n][y_n].tag == 0) {
if(min == -1 || min > map[x_n][y_n].distance) {
min = map[x_n][y_n].distance;
min_x = x_n;
min_y = y_n;
}
}
}
}
}
map[min_x][min_y].tag = 1;
set[count][0] = min_x;
set[count][1] = min_y;
count++;
for(int i = 0; i < 8; i++) {
x_n = min_x + position[i][0];
y_n = min_y + position[i][1];
if(x_n >= 0 && x_n < 8 && y_n >= 0 && y_n < 8) {
if(map[x_n][y_n].tag == 0) {
if(map[x_n][y_n].distance == -1 ||
map[x_n][y_n].distance > map[min_x][min_y].distance + 1) {
map[x_n][y_n].distance = map[min_x][min_y].distance + 1;
}
}
}
}
}
}
/*
* The main program.
*/
int main(void) {
chess1 = (chess**) malloc(sizeof(chess*) * 8);
for(int i = 0; i < 8; i++) {
chess1[i] = (chess*) malloc(sizeof(chess) * 8);
}
chess2 = (chess**) malloc(sizeof(chess*) * 8);
for(int i = 0; i < 8; i++) {
chess2[i] = (chess*) malloc(sizeof(chess) * 8);
}
chess3 = (chess**) malloc(sizeof(chess*) * 8);
for(int i = 0; i < 8; i++) {
chess3[i] = (chess*) malloc(sizeof(chess) * 8);
}
int t;
scanf("%d", &t);
for(; t > 0; t--) {
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
chess1[i][j].distance = chess2[i][j].distance
= chess3[i][j].distance = -1;
chess1[i][j].tag = chess2[i][j].tag
= chess3[i][j].tag = 0;
}
}
char location[3];
scanf("%s", location);
dijkstra(chess1, location[0] - 'A', location[1] - '1');
scanf("%s", location);
dijkstra(chess2, location[0] - 'A', location[1] - '1');
scanf("%s", location);
dijkstra(chess3, location[0] - 'A', location[1] - '1');
int min = -1;
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++) {
int s = chess1[i][j].distance + chess2[i][j].distance
+ chess3[i][j].distance;
if(min == -1 || min > s) {
min = s;
}
}
}
printf("%d\n", min);
}
return 0;
}