1.八皇后问题
- 八皇后问题是一个以国际象棋为背景的问题:如何能够在8*8的国际象棋的棋盘上放置8个皇后,使得任何一个皇后都无法直接吃掉其他的皇后?为了达到此目的,任意两个皇后都不能处于同一条横行、纵行或者斜线上。
2.回溯递归法(传统方法)
- (1)从第一列开始,为皇后找到安全位置|y1-y2|!=|x1-x2|,然后跳到下一列
不能是同一行,同一列,同一个斜线 - (2)如果在第n列出现死胡同,如果该列为第一列,棋局失败,否则后退到上一列,在进行回溯
- (3)如果在第8列找到了安全位置,则棋局成功。
- 回溯是C语言的方法
3.C++算法:next_permutation
-
next_permutation,得到下一个排列
全排列 -
8个数字可以表示棋盘上的坐标,两两比较这些坐标是否是互斥的,如果都是互斥的,说明他是其中的一个解。
皇后的坐标表示(y,x),y表示序号,x表示值,eg:(7,5)表示下标为7,值是5
图中的任意2个坐标不可能在同一行,也不可能在同一列,因为这是由上面表示的方式决定的。
如何判定2个坐标在同一个斜线上面呢?
可以用|y1-y2| = |x1-x2|,斜率是45°,说明是在同一条斜线上面。
两两比较,(0,0)和(1,1),(2,2)比较以此类推。如果都不在同一条斜线上面,说明这一组坐标是一个解。
再生成下一个排列继续求解。
-
这是由循环来解决的。
-
eg:P81\01.cpp
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void print_element(int n)
{
cout <<n<<' ';
}
int main(void)
{
int a[] = {1,2,3,4};
vector<int> v(a,a+4);
for_each(v.begin(), v.end(), print_element);
cout <<endl;
//编序型算法
while (next_permutation(v.begin(), v.end()))
{
for_each(v.begin(), v.end(), print_element);
cout<<endl;
}
}
-
测试:1,2,3,4输出有24种排列
-
eg:P81\02.cpp
#include <cmath>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAX = 8;
//表示棋盘向量,8个元素的值都是为0
vector<int> board(MAX);
void show_result()
{
//i表示y,board[i]表示x
for(size_t i = 0; i < board.size(); i++)
{
cout<< "(" << i << "," << board[i] << ")";
}
cout << endl;
}
//使用循环来解
int check_cross()
{
//这种坐标表示方法,表示他们既不在同一行也不在同一列
//这里的j和i都代表y坐标,就是行
for (size_t i = 0; i < board.size(); i++)
{
for (size_t j = i + 1; j < board.size(); j++)
{
//y坐标相减是否等于x坐标相减
if ((j-i) == (size_t)abs(board[j] - board[i]))
return 1;
}
}
return 0;
}
void put_chess()
{
while(next_permutation(board.begin(), board.end()))
{
//这个排列所代表的坐标是否有界
//判断是否是一个解
if(!check_cross())
{
show_result();//若是解,则打印坐标
}
}
}
int main()
{
//初始化为0-7
for(size_t i = 0; i < board.size(); i++)
{
board[i] = i;
}
//将棋子放到棋盘上面,即生成下一个排列
put_chess();
return 0;
}
- 测试:
8皇后问题总共有92个解
把第一个解画一下