八皇后非递归解法

问题描述:

在8*8的国际象棋棋盘上,现要放上8个皇后,要求所有皇后都不得在同一行、一列、一斜线上,输出所有可能的放法。

方法:

逐行试探,行就不用考虑了,只需要考虑每次放置时是不是有同列、同斜线的。因为如果按照行去排,给这行放一个就可以跳到下一行了。

图:

分析:

1. 从0行开始,有8个格子,1个1个试探。(0,0)可以吗? 可以 break;

2. 到第一行:(1,0)可以吗?不可以,有重复列。 (1,1)可以吗?不可以,同斜线。 (1,2)可以吗?可以 break;

3. 到第二行:(2,0)可以吗?不可以,同列。(2,1)可以吗?不可以,同斜线。 (2,2)可以吗?不可以,同列。(2,3)可以吗?不可以,同斜线。 (2,4) 可以吗?可以 break;

4. 下一行列号都是从0开始

......

当某一行都不可以放的时候,即(j > 7)则需要回溯到上一行,给上一行的重新再挑选位置。新位置一定在之前的位置之后。

直到第7行,放置结束,输出这组解。

非递归的算法思想(输出一种结果即可):

  1. 行:不用管,放了就 i++ 到下一行。
  2. 列:有两种判断方法。
  • 一:循环此列从 0 到 i-1,找这一列上有没有放过皇后。
  • 二:把全部列状态存放在数组中,因为不会出现两个在一列,所以此数组只有两个状态:0 此列没有存,  1  此列存放过了

    斜线:斜线分为左斜线和右斜线。左斜线如下图:

总共15条,从左到右编号0-14。与下标的关系(i+j)。0 此斜线上没有存,  1  此斜线上存放过了。

右斜线如下图:

 总共15条,从右下角到左上角编号0-14。与下标的关系(7+i-j)。0 此斜线上没有存,  1  此斜线上存放过了。

Q

栈,用于存放此次的结果,Q栈的下标代表行号,值代表此行中皇后放在 j 列。

因为如果回溯,需要用到上次的位置,属于后进先出,所以用栈。

 每次准备放置一个皇后在选好的位置,就需要更新Q、col、left、right。

 代码:

# include <stdio.h>
# include <stdlib.h>
// 所有都是从0开始编号 

// 在c语言中,给数组赋初值时,可以只写一个,这样后面的也就系统自动赋初值为此值 
int col[8] = {0,0,0,0,0,0,0,0};				//第i列有没有放皇后,0表示没放,1表示放了  
int left[15] = {0}; 					//左斜线i上有没有皇后,0表示没放,1表示放了
int right[15] = {0};					//右斜线i上有没有放皇后,0表示没放,1表示放了 
int Q[8] = {-1};					//第i行第Q【i】列上放的皇后 

void Queen();
void print(); 

int main(void){
	// 非递归遍历,此代码只显示一次的结果,要是需要所有可能结果,就需要改第一行开始放的位置
	Queen();	// 调用放置皇后的函数
	print();	// 调用打印函数,可打印棋盘 
	 
	return 0;
} 

void Queen(){
	int top = -1;	// 因为当回溯时,需要回到上一层的位置,并重新确定位置。Q就相当于栈,满足后进先出的特点 
	int i = 0;		// i表示现在在判断第i行 
	int j = 0; 		// j表示现在在判断第i行的第j列 
	
	while(top != 7){// top从 -1 开始指,当指到7的时候意味着7行都已经放上了皇后,得到了一次的结果
		// 试探这一行的每一列
		for(;j < 8; j++){	
		//j为什么不能直接从0开始?因为只有到了新的一行才能从0开始,如果是回溯回来的就需要从上一次的位置向后走
			if(!col[j] && !left[i+j] && !right[7+i-j]){	// 能放 
				// 放置皇后	
				Q[++top] = j;
				
				// 修改状态 
				col[j] = 1;
				left[i + j] = 1;
				right[7+i-j] = 1;	
				
				// 走下一行 
				i++;	
				j = 0; 	// 新的一行j从0开始 
				break;	// 退出for循环 
			}	
		} 
		
		// 如果是这一行都不能放,就需要回溯 
		if(j == 8){	// 如果不加if的话,break就会跳到这里,而不是下一层 
			j = Q[top--];	// 取栈顶
			i--;			// 退到上一层 
			// 上一层的改回去 
			col[j] = 0;
			left[i + j] = 0;
			right[7+i-j] = 0; 
			
			j++; // 从下一格开始走 
		} 
	}
}
	
// 打印函数:打印方阵 
void print() {
	int i,j;
	printf("第1组解:\n");
	for(i = 0; i < 8; i++){
		for(j = 0; j < 8; j++){
			if(Q[i] == j){
				printf("Q ");
			}else {
				printf("x ");
			}
		}
		printf("\n");
	} 
} 

运行结果:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值