马踏棋盘(回溯法)

题目:

编写一个演示国际象棋中马踏棋盘的程序。

问题描述:

将马随机放在国际象棋的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"); 
} 

输入:(无输入)

输出:

 

 

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值