八皇后问题(减支思想、全列举)

八皇后问题描述:

给出n*n的棋盘,在上面摆放n个棋子,每个棋子在棋盘上不能处于同一行列或对角线上。

举个n=4的例子:

八皇后问题(减支思想、全列举)_第1张图片

如图就是n=4时符合情况的一种情况。

解决思想:

1.减支思想:

通过分析减少不必要的暴力搜索降低算法地复杂度

①、共有n*n个格子,需摆放n个棋子,就是说考虑不同行摆放的话会有n^n种情况;

②、再考虑也不能同列的情况,会有n!种情况。

2.信息浓缩:

通过适当的表示方法减少编程的复杂度(其实就是选择合适的数据结构)

这道题可以考虑使用数字记录棋子在该行的位置,比如上图可以考虑记录为(2,4,1,3)

难点:

思想比较简单,主要是全列举有点难。

全列举就是把减支思想提到n!种情况全部列举出来。

解决办法:通过递归。

八皇后问题(减支思想、全列举)_第2张图片

图片是一部分过程,每个done!!!!表示一次列举完成,可以看到,思想是将1,2,3,4几个数字依次放入数组中。一次举例完成后,某一数字后移一位,比如第二次就是1,2不动,3后移一位,4填补上空缺。接下来是1不动,2后移一位,3,4填不上空缺。

最后检测是否满足条件比较简单,直接上代码。

之所以记录下来是因为全列举对我来说还需要列举,空手写递归的能力不是很足,写递归的时候有好多细节会遗漏。

#include 
#include "stdafx.h"
#include 
#include 

using namespace std;

int n = 0; //棋盘行列数

void check_map(int* map)
{
	//检查棋盘(正反向对角线不相撞)
	for (int i = 0; i < n; i++)
	{
		for (int j = i + 1; j < n; j++)
			if (map[i] - map[j] == i - j || map[i] - map[j] == j - i)
				return;
	}
	for (int i = 0; i < n; i++)
		cout << map[i] << " ";
	cout << endl;
}

void set_map(int start, int count, int* map)
{
	for (int i = 0; i < n; i++)		//将不比count小的数置0
	{
		if (map[i] >= count)
			map[i] = 0;
	}
	//check_map(map);	//观察列举的过程
	if (count == n)		//若count已经是最后一位数,则只放入并检测
	{
		for (int i = start; i < n; i++)
		{
			if (map[i] == 0)
			{
				map[i] = count;
				break;
			}
		}
		//Sleep(1000);
		check_map(map);
		//cout << "done!!!!" << endl;
		return;
	}
	if (count < n)	//若count不是最后一位,则放入数据之后调用set_num(0,count+1),然后调用set_num(start+1,count)
	{
		for (int i = start; i <= n; i++)
		{
			if (map[i] == 0)
			{
				map[i] = count;
				start = i;	//更新一下start
				break;
			}
			if (n == i)	//若后面的位置都被占了,说明举例完成,直接退出
				return;
		}
		set_map(0, count + 1,map);	//从位置0开始寻找可以放入的位置
		if(start+1> n;
	int* map = new int[n];
	memset(map, 0, n * sizeof(int));
	set_map(0, 1, map);
	cin >> n;
	return 0;
}



你可能感兴趣的:(算法)