八皇后问题,是一个古老而著名的问题,是回溯算法的典型案例。该问题是国际西洋棋棋手马克斯·贝瑟尔于1848年提出:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。 高斯认为有76种方案。1854年在柏林的象棋杂志上不同的作者发表了40种不同的解,后来有人用图论的方法解出92种结果。
思路:一般来说,八皇后问题使用递归或者递推的方法,一:在棋盘某位置放一个皇后;二:判断皇后是否与前面已有皇后形成相互攻击;三:如果没有相互攻击,则调用递归函数,继续放置下一列皇后;四:放置完8个不形成攻击的皇后,变得到一个解。
如果我们设置一个数组arr[8],每个元素的值代表棋牌中该行所放置皇后的位置,例如arr[1]=2,说明第二行(下标从0开始)放置位置为第三列(下标同样从0开始)。自然可以枚举出所有排列顺序,进行判断,但是如何枚举所有顺序呢?这里用到了C++中next_permutation函数。我们用string s=“01234567”代表第一次的位置进行判断,如果不合适,使用next_permutation排序成01234576进行循环,依次类推,知道所有可能排序枚举完为止。
#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
int ans = 0;
int _tmain(int argc, _TCHAR* argv[])
{
string s = "01234567";
int arr[8];
int flag = 1; //当前位置是否可以存放皇后的标志
do{
flag = 1;
for (int i = 0; i < 8; i++)
{
arr[i] = s[i] - '0'; //将char类型转换成int类型,存放到arr数组中
for (int j = 0; j < i; j++)
{
if (abs(i - j) == abs(arr[i] - arr[j])) //如果在同一列或者对角上,flag=0,不合适
{
flag = 0;
break; //如果不合适,后面的行无需放置,跳出本次循环,结束后面行的比较
}
}
if (flag == 0) //如果是不合适跳出来的,说明这个顺序不合适,跳出进行next_permutation
break;
if (i == 7 && flag == 1) //如果flag=1而且i=7,说明进行到最后一行并且本次顺序合适,结果加1
{
ans++;
}
}
} while (next_permutation(s.begin(), s.end())); //获得下一个顺序
cout << ans << endl;
return 0;
}