1.Intro
这是由国际西洋棋棋手marks在1848年提出的一个问题。在8x8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行同一列或同一斜线上,问有多少种摆法。我们计算机编程来解决这个问题。
2.Solution
首先尝试暴力直接法,8个循环嵌套,状态空间在8^8,so huge,弃用。
略加思考,可以用回溯来解决的奥。
回溯backtrack是说
result=[]
def fuc(路径,选择列表):
if 满足结束条件:
result.add(路径)
for 选择 in 选择列表:
做选择
fuc(路径,选择列表)
撤销选择
回溯用了递归,for循环里递归,在递归前做选择,递归调用结束后撤销选择。
尝试使用回溯来解决八皇后问题,写代码:
#includeusing namespace std; short arr[8]; int result = 0; bool isValid(int x,int y){ if(x==0){ return 1; } for(int i=0;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< 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——————暂时只想写回溯这一种解法,可能以后还会扩充其他的吧。
3.Extension
好,找到了八皇后的可行解法,接下来推广到n皇后问题。
只要把上面代码的8全换成这个n就好啦