回溯 N皇后问题

52 篇文章 0 订阅
6 篇文章 0 订阅

问题描述

会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。 对于某个满足要求的8皇后的摆放方法,定义一个皇后串a与之对应,即a=b1b2…b8,其中bi为相应摆法中第i行皇后所处的列数。已经知道8皇后问题一共有92组解(即92个不同的皇后串)。给出一个数b,要求输出第b个串。串的比较是这样的:皇后串x置于皇后串y之前,当且仅当将x视为整数时比y小。 
输入数据
第1行是测试数据的组数n,后面跟着n行输入。每组测试数据占1行,包括一个正整数b(1 <= b <= 92)
输出要求
n行,每行输出对应一个输入。输出应是一个正整数,是对应于b的皇后串
输入样例
2
1
92


输出样例
15863724
84136275

      分析:从n×n个格子中选择n个格子摆放皇后。可见解空间树为子集树。

      使用maze[MAX][MAX]来表示棋盘,maze[i][j]=0 表示(I,j)位置为空,maze[i][j]=1 表示(I,j)位置摆放有一个皇后。

      全局变量way表示总共的摆放方法数目。

      使用queen(t)来摆放第t个皇后。queen(t) 函数符合子集树时的递归回溯范式。当t>N时,说明所有皇后都已经摆   放完成,这是一个可行的摆放方法,输出结果;否则,遍历棋盘,找皇后t所有可行的摆放位置,placeQueen(i,j) 判断皇后t能否摆放在位置(i,j)处,如果可以摆放则继续递归摆放皇后t+1,如果不能摆放,则判断下一个位置。

       placeQueen(row,col)函数首先判断位置(row,col)是否合法,继而判断(row,col)处是否已有皇后,有则冲突,返回0,无则继续判断行、列、斜方向是否冲突。斜方向分为左上角、左下角、右上角、右下角四个方向,每次从(row,col)向四个方向延伸一个格子,判断是否冲突。如果所有方向都没有冲突,则返回1,表示此位置可以摆放一个皇后。

        代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
# define MAX  4
int maze[MAX][MAX];//棋盘 0表示空白 1表示有皇后
int placeQueen(int row, int col){
	int i,j;
	if(maze[row][row] == 1)
		return 0;
	for(j=0; j<MAX; j++)//同一行
		if(maze[row][j] == 1)
			return 0;
	for(i=0; i<MAX; i++)//同一列
		if(maze[i][col] == 1)
			return 0;
			
	
	/* i表示从当前点(row,col)向四个斜方向扩展的长度 
	  
	左上角 \  / 右上角   i=2 
	        \/           i=1 
	        /\           i=1 
	左下角 /  \ 右下角   i=2 
	*/  
	for(i=1; i<MAX; i++)//左上 
		if((row-i >= 0) && (col-i >= 0))
			if(maze[row-i][col-i] == 1)
				return 0;
	for(i=1; i<MAX; i++)//右上
		if((row-i >= 0) && (col+i < MAX))
			if(maze[row-i][col+i] == 1)
				return 0;
	for(i=1; i<MAX; i++)//左下
		if((row+i < MAX) && (col-i >= 0))
			if(maze[row+i][col-i] == 1)
				return 0;
	for(i=1; i<MAX; i++)//右下 
		if((row+i < MAX) && (col+i < MAX))
			if(maze[row+i][col+i] == 1)
				return 0;
	return 1;
}

void queen(int nowQueen){
	if(nowQueen > MAX){//放置完成 
		printf("完成一次配置\n"); 
		for(int i=0; i<MAX; i++){
			for(int j=0; j<MAX; j++)
				printf("%3d",maze[i][j]);
			printf("\n");
		}
	} else{ 
		for(int i=0; i<MAX; i++)
			for(int j=0; j<MAX; j++)
				if(placeQueen(i,j)){//能放置 
					maze[i][j] = 1;
					queen(nowQueen + 1);
					maze[i][j] = 0;
				}
	}
}
int main(){
	int i,j,count;
	memset(maze,0,sizeof(maze));
	queen(1);//放置第一个皇后 
	printf("\n");
}


该问题还有更优的解法。充分利用问题隐藏的约束条件:每个皇后必然在不同的行(列),每个行(列)必然也只有一个皇后。这样我们就可以把N个皇后放到N个行中,使用Pos[i]表示皇后i在i行中的位置(也就是列号)(i = 0 to N-1)。这样代码会大大的简洁,因为节点的子节点数目会减少,判断冲突也更简单。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值