八皇后问题描述:
给出n*n的棋盘,在上面摆放n个棋子,每个棋子在棋盘上不能处于同一行列或对角线上。
举个n=4的例子:
如图就是n=4时符合情况的一种情况。
解决思想:
1.减支思想:
通过分析减少不必要的暴力搜索降低算法地复杂度
①、共有n*n个格子,需摆放n个棋子,就是说考虑不同行摆放的话会有n^n种情况;
②、再考虑也不能同列的情况,会有n!种情况。
2.信息浓缩:
通过适当的表示方法减少编程的复杂度(其实就是选择合适的数据结构)
这道题可以考虑使用数字记录棋子在该行的位置,比如上图可以考虑记录为(2,4,1,3)
难点:
思想比较简单,主要是全列举有点难。
全列举就是把减支思想提到n!种情况全部列举出来。
解决办法:通过递归。
图片是一部分过程,每个done!!!!表示一次列举完成,可以看到,思想是将1,2,3,4几个数字依次放入数组中。一次举例完成后,某一数字后移一位,比如第二次就是1,2不动,3后移一位,4填补上空缺。接下来是1不动,2后移一位,3,4填不上空缺。
最后检测是否满足条件比较简单,直接上代码。
之所以记录下来是因为全列举对我来说还需要列举,空手写递归的能力不是很足,写递归的时候有好多细节会遗漏。
#include <cstring>
#include "stdafx.h"
#include <iostream>
#include <windows.h>
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)
set_map(start + 1, count,map); //尝试下一个可以放入的位置*/
}
}
int main(void)
{
cin >> n;
int* map = new int[n];
memset(map, 0, n * sizeof(int));
set_map(0, 1, map);
cin >> n;
return 0;
}