码迷,mamicode.com
首页 > 其他好文 > 详细

八皇后问题

时间:2015-06-25 12:31:24      阅读:91      评论:0      收藏:0      [点我收藏+]

标签:八皇后   算法   递归   回溯   

问题抛出:在棋盘上放置8个皇后,使得它们互不攻击,此时每个皇后的攻击范围为同行同列和同对角线,要求找出所有解。如图所示:

技术分享

【分析】

最简单的方法是把问题转化为“从64个格子中选一个子集”,使得“子集中恰好有8个格子,且任意两个选出的格子都不在同一行、同一列、或同一个对角线上”。这正是子集枚举问题。然而,64个格子的子集有2^64个,数量级有10^19,太大了,这并不是一个很好的模型。

简化:把问题转化为“从64个格子中选8个格子”,这是组合生成问题。根据组合数学,有8C64 = 4.426*10^9种方案,少很多了,很还不够少。

再简化:观察规律,恰好每行每列各放置一个皇后。如果用C[x]表示第x行皇后的列编号,则问题变成了全排列生成问题。而0~7的排列一共只有8!=40320个,枚举量不会超过它。

注意:当把问题分成若干步骤并递归求解时,如果当前步骤没有合法选择,则函数将返回上一级递归调用,这种现象成为回溯。正是因为这个原因,递归枚举算法常被成为回溯(backtracking)法,应用十分普遍。


demo 1

#include <iostream>
#include <cstdio>
using namespace std;

int n, tot;
int C[8];

void search(int cur)
{
	if (cur == n) { // 递归边界。只要走到这里,所有皇后必然不冲突
		tot++;
	}
	else for (int i = 0; i < n; i++) {
		bool ok = true;
		C[cur] = i; // 尝试把第cur行的皇后放在第i列
		for (int j = 0; j < cur; j++) { // 检查是否和前面你的皇后冲突
			if (C[cur] == C[j] ||
				cur - C[cur] == j - C[j] || // 主对角线判定
				cur + C[cur] == j + C[j]) { // 副对角线判定
				ok = false;
				break;
			}
		}
		if (ok) {
			search(cur + 1);
		}
	}
}

int main()
{
	cin >> n;
	tot = 0;
	search(0);
	cout << tot << endl;
	return 0;
}

注意:既然是逐行放置的,则皇后肯定不会横向攻击,因此只需检查是否纵向和斜向攻击即可。

结点数现在很难减少了,但程序效率可以继续提高;利用二维数组vis[2][]直接判断当前尝试的皇后所在的列和两个对角线是否已有其他皇后。注意到主对角线标识y-x可能为负数,存取时要加上n。

demo 2

#include <iostream>
#include <cstdio>
using namespace std;

int n, tot;
int C[8];
int vis[3][15];

void search(int cur)
{
	if (cur == n) {
		tot++;
	}
	else for (int i = 0; i < n; i++) {
		if (!vis[0][i] && !vis[1][cur + i] && !vis[2][cur - i + n]) {
			C[cur] = i;
			vis[0][i] = vis[1][cur + i] = vis[2][cur - i + n] = 1; // 修改全局变量
			search(cur + 1);
			vis[0][i] = vis[1][cur + i] = vis[2][cur - i + n] = 0; // 记得改回来
		}
	}
}

int main()
{
	cin >> n;
	tot = 0;
	memset(vis, 0, sizeof(vis));
	search(0);
	cout << tot << endl;
	return 0;
}

demo 2程序有个及其关键的地方:vis数组的使用,vis数组的确切含义:它表示已经放置的皇后占据了哪些列、主对角线和副对角线。将来放置的皇后不应该修改这些值。一般地,如果在回溯法中修改了辅助的全局变量,则一定要及时把它们恢复原状(除非故意保留所做修改)。另外,在调用之前一定要把vis数组清空。


注意:如果在回溯法中使用了辅助的全局变量,则一定要及时把它们恢复原状。特别地,若函数有多个出口,则需要在每个出口处恢复被修改的值。

八皇后问题

标签:八皇后   算法   递归   回溯   

原文地址:http://blog.csdn.net/zyq522376829/article/details/46633265

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!