马踏棋盘 回溯 递归与非递归 -全解-c语音

问题描述:

在 8×8 的国际象棋棋盘上,用一个马按照马步跳遍整个棋盘,要求每个格子都只跳到一次,并且全部跳完。

解法思路:

  在8x8的棋盘上,左上角的马能走的位置肯定比中间或其他地方要少的,所以为了简化问题与减少算法所需时间,我们把棋盘扩充为12x12的,那么在正中间的8x8棋盘中,我们能够让每一匹马都有八个方位能走。再把这八个位置的偏量放置一个数组里面方便计算。递归与非递归的思路是相似的,只是非递归需要借助栈来记录上一步的位置,以及上一步到当前步的循环变量 i 的值。
// 马的八个方向 
int move[8][2]={{1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2}};

在这里插入图片描述


递归代码:

#include<stdio.h>

// 棋盘,马走的位置 
int chess[12][12]={0};

// 记录走了多少步 
int cnt = 0;

// 记录有多少种解
int countChess = 0; 

// 马的八个方向 
int move[8][2]={{1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2}};

// 初始化棋盘 
int initChess();
// 输出解
void printChess(); 
// 马踏棋盘
void horse(int x, int y); 

int main(void){
	initChess();
	int i,j;
	// 循环给马放初始位置
	for(i-2; i<10; i++){
		for(j=2; j<10; j++){
			// 先把马放在初始位置
			cnt = 1;
			chess[i][j] = cnt;
			horse(i,j);
		}
	}	
}

void horse(int x, int y){
	int i, j;
	// 循环八个方向,寻找能走的方向 
	for(i=0; i<8; i++){
		// 马下一步可能要走的位置坐标
		int row = x + move[i][0];
		int col = y + move[i][1];
		
		// 判断当前方向能不能走 
		if(chess[row][col] == 0){
			// 能走
			chess[row][col] = ++cnt;
		
			// 判断走后位置是不是最后一个位置
			if(cnt == 64){
				// 是,输出
				++countChess;
				printChess();
				
				// 抹掉走后位置的值,以便寻找下一个解
				cnt--;
				chess[row][col] = 0;
				
				// 剩余位置已不可能有位置,退出当前循环
				break; 
			} else{
				// 不是最后一个位置
				
				// 继续向下走
				horse(row, col);
				
				// 如果程序回到这儿,说明上一步已经走完,或者得不到解,那么当前位置就是不在需要的,或者说错的,抹掉
				cnt--;
				chess[row][col] = 0;
			}
		} 
	}

}

int initChess(){
	int i,j;
	for(i=0; i<12; ++i){
		for(j=0; j<12; ++j){
			if(i<2 || i>9 || j<2 || j>9){
				chess[i][j]=-1;
			}
		}
	}
}

void printChess(){
	printf("第%d个解是:\n", countChess);
	int i,j;
	for(i=2; i<10; ++i){
		for(j=2; j<10; ++j){
			printf("%2d ",chess[i][j]);
		}
		printf("\n");
	}
	printf("***********************\n");
}


非递归代码:

#include<stdio.h>

// 棋盘,马走的位置 
int chess[12][12]={0};

// 记录走了多少步 
int cnt = 0;

// 记录有多少种解
int countChess = 0; 

// 马的八个方向 
int move[8][2]={{1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2}};

// 初始化棋盘 
int initChess();
// 输出解
void printChess(); 
// 马踏棋盘
void horse(int x, int y); 


// 用于存入上一步操作的各个值,其实只用得到63个,因为永远不会存入最后一个,只是用来辅助作用,也可以用来输出,但是格式不好表达,所以就只用来辅助 
struct Node{
	// 存储马走过的坐标 
	int x;
	int y;
	
	// 走到当前步的i值,回溯时会用 
	int i;
}chessStep[64];
// 模拟栈顶指针 
int top = -1;


int main(void){
	initChess();
	int i,j;
	// 循环给马放初始位置
	for(i=2; i<10; i++){
		for(j=2; j<10; j++){
			// 先把马放在初始位置
			cnt = 1;
			chess[i][j] = cnt;			
			horse(i,j);
		}
	}
	
}

void horse(int x, int y){
	int i = 0;
	// 循环八个方向,寻找能走的方向 
	while(cnt < 64){
		int row;
		int col;
		for(i; i<8; i++){
			// 马下一步可能要走的位置坐标
			row = x + move[i][0];
			col = y + move[i][1];
			if(chess[row][col] == 0){
				break;
			}
		}  
		if(i != 8){
			// 能走
			chess[row][col] = ++cnt;
			chessStep[++top].x = x;
			chessStep[top].y = y;
			chessStep[top].i = i;
			
			
			// 判断走后位置是不是最后一个位置
			if(cnt == 64){
				// 是,输出
				printChess();
				
				// 抹掉走后位置的值,以便寻找下一个解
				chess[row][col] = 0;
				
				i = chessStep[top].i + 1;
				x = chessStep[top].x;
				y = chessStep[top].y;
				
				top--;
				cnt--;
			}else{
				// 不是最后一个位置
					
				// 继续向下走
				x = row;
				y = col;
				i = 0;
			}
		}else{
			chess[x][y] = 0;

			i = chessStep[top].i + 1;
			x = chessStep[top].x;
			y = chessStep[top].y;
				
			top--;
			cnt--;
		}
		
		// 循环终极退出条件,当程序运行到需要换第一个马的位置是,top--会到-1 
		if(top == -1){
			break;
		} 
	}	
}

int initChess(){
	int i,j;
	for(i=0; i<12; ++i){
		for(j=0; j<12; ++j){
			if(i<2 || i>9 || j<2 || j>9){
				chess[i][j]=-1;
			}
		}
	}
}

void printChess(){
	++countChess;
	printf("第%d个解是:\n", countChess);
	int i,j;
	for(i=2; i<10; ++i){
		for(j=2; j<10; ++j){
			printf("%2d ",chess[i][j]);
		}
		printf("\n");
	}
	printf("***********************\n");
}


输出结果:

注:程序得很久很久才能跑完所有解,这只几分钟的结果图。

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值