<基础><回溯>八皇后问题

1.Intro

这是由国际西洋棋棋手marks在1848年提出的一个问题。在8x8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行同一列或同一斜线上,问有多少种摆法。我们计算机编程来解决这个问题。

2.Solution

首先尝试暴力直接法,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——————暂时只想写回溯这一种解法,可能以后还会扩充其他的吧。

3.Extension

好,找到了八皇后的可行解法,接下来推广到n皇后问题。

只要把上面代码的8全换成这个n就好啦
posted @ 2020-01-01 16:22  dynmi  阅读(303)  评论(0编辑  收藏  举报