rein0 2020-01-01
这是由国际西洋棋棋手marks在1848年提出的一个问题。在8x8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行同一列或同一斜线上,问有多少种摆法。我们计算机编程来解决这个问题。
首先尝试暴力直接法,8个循环嵌套,状态空间在8^8,so huge,弃用。
略加思考,可以用回溯来解决的奥。
回溯backtrack是说
result=[]def fuc(路径,选择列表): if 满足结束条件: result.add(路径) for 选择 in 选择列表: 做选择 fuc(路径,选择列表) 撤销选择
回溯用了递归,for循环里递归,在递归前做选择,递归调用结束后撤销选择。
尝试使用回溯来解决八皇后问题,写代码:
#include<bits/stdc++.h>
using namespace std;
short arr[8];
int result = 0;
bool isValid(int x,int y){
if(x==0){
return 1;
}
for(int i=0;i<x;i++){
if(arr[i]==y | abs(arr[i]-y)==abs(i-x)){
return 0;
}
}
return 1;
}
void fuc(int col){
if(col==8){
result++;
return;
}
for(int i=0;i<8;i++){
if(isValid(col,i)){
arr[col]=i;
fuc(col+1);
}
}
}
int main(){
fuc(0);
cout<<result<<endl;
return 0;
}在上面的代码中,我们秉承着这样的思路去解决问题:先看第0列,再看第1列,在看第2列一直到第7列。在每一列上放一颗皇后。
arr[8]数组表示着棋盘的摆放情况,比如说arr[3]=6则表示(3,6)位置上有一颗皇后;
result是计数变量,当发现一种可行方案后就给result++;
isValid(int x,int y)函数用来判断看x列的时候如果皇后放在(x,y)位置会不会与前x-1列冲突,可以放就返回1,不可以放就返回0;
fuc(int col)函数是主体,代表着看到第col列的时候的情况。
从这里也可以看得出来,回溯算法其实也算是暴力穷举,复杂度较高,因为其中用到了递归速度肯定不能算快,另外它不像DP存在重叠子问题可以优化。
emmm——————暂时只想写回溯这一种解法,可能以后还会扩充其他的吧。
好,找到了八皇后的可行解法,接下来推广到n皇后问题。
只要把上面代码的8全换成这个n就好啦