题目:
编写一个演示国际象棋中马踏棋盘的程序。
问题描述:
将马随机放在国际象棋的8*8棋盘的某个方阵中,马按走棋规则(走“日”字)进行移动,要求每个方格只能进入一次,走遍棋盘上全部64个方格,求出马的行走路线,将数字1-64按照马走的顺序输出在8*8的方阵中。
提示:
由于可能性太大,如果把进入的地址随机,这样的程序跑起来跑个一天一夜估计也结束不了,可能会导致卡机。所以,下面的代码就是确定了入口(2,2),如果不想确定入口,就用二重循环随机指定入口即可。
马移动的八种可能:
8*8的棋盘:
可以看到,不是所有的格子都有八种可能的走法。
所以我们有两种选择:
1. 每次判断此格子是特殊格子,然后确定它可能的走法。
2. 添加四行四列(上面两行,下面两行,左边两列,右边两列),这样使得所有格子都有八种走法。但是新添加的格子是不可以走的。
显然第二种方法更好实现,实现方法(八叉树):
新添加的格子都初始化为-1, 中间的格子初始化为0。这样-1就代表这个格子不能走。
当马走到这个格子上时,给这个格子标记为(1-64),即这是马走的第几个格子。
这样,马会试探八种可能走法,只有格子为0时(即此格子不是添加的假格子,也没有走过),马就往这个格子上走。
直到所有八种走法都不能走时,回溯,说明上一步走的不对,重新选上一步。
可能的移动位置Move数组:
意思是:假设当前马的位置是(x,y),马可能走的位置为:(x+2,y+1)(x+1,y+2)......
解法:
遍历八叉树
代码实现:
# include <stdio.h>
int cnt = 0; // 标记第几步
int tip = 1; // 标记这是第几种可能的输出
int Move[8][2]; // 保存八种走法
int H[12][12]; // 十二行、十二列的棋盘
void print();
void House(int x, int y);
int main (void){
/*第一步:初始化棋盘*/
int i,j;
// 上面两行为-1
for (i = 0; i < 2; i++) {
for (j = 0; j < 12; j++) {
H[i][j] = -1;
}
}
// 下面两行为-1
for (i = 10; i < 12; i++) {
for (j = 0; j < 12; j++) {
H[i][j] = -1;
}
}
// 左边两列为-1
for (i = 0; i < 12; i++) {
for (j = 0; j < 2 ; j++) {
H[i][j] = -1;
}
}
// 右边两列为-1
for (i = 0; i < 12; i++) {
for (j = 10; j < 12; j++) {
H[i][j] = -1;
}
}
// 中间为0
for (i = 2; i < 10; i++) {
for (j = 2; j < 10; j++) {
H[i][j] = 0;
}
}
// 第二步,初始化八种走法
Move[0][0] = 2; Move[0][1] = 1; // {x+2,y+1}
Move[1][0] = 1; Move[1][1] = 2; // {x+1,y+2}
Move[2][0] = -1; Move[2][1] = 2; // {x-1,y+2}
Move[3][0] = -2; Move[3][1] = 1; // {x-2,y+1}
Move[4][0] = -2; Move[4][1] = -1; // {x-2,y-1}
Move[5][0] = -1; Move[5][1] = -2; // {x-1,y-2}
Move[6][0] = 1; Move[6][1] = -2; // {x+1,y-2}
Move[7][0] = 2; Move[7][1] = -1; // {x+2,y-1}
// 第三步,给定初始位置,调用回溯函数
H[2][2] = ++cnt; // 先走上去
House(2,2); // 从这一步,向下调用
return 0;
}
void House(int x, int y){
if(cnt == 64){
print();
return;
}
int i;
for(i = 0; i < 8; i++){ // 把每一种走法都走一遍,八叉树
// 计算准备要走的这一步的位置
int a = x + Move[i][0];
int b = y + Move[i][1];
if(H[a][b] == 0) { // 能走
H[a][b] = ++cnt; // 标记
House(a,b); // 向下走
H[a][b] = 0; // 退回来,还原状态
cnt--; // 对称处理
}
}
}
// 打印棋盘
void print(){
int i,j;
printf("第%d个:\n\n", tip++);
for (i = 2; i < 10; i++) {
for (j = 2; j < 10; j++) {
if (H[i][j]< 10) printf(" %d ", H[i][j]);
else printf("%d ", H[i][j]);
}
printf("\n");
}
printf("\n\n");
}
输入:(无输入)
输出: