八皇后问题的n种解法

 经典的八皇后问题:在8×8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。

很早就接触过八皇后问题,最近数据结构作业中又看到了这个题目,仔细研究了一波网上诸位大牛的博客,发现这个问题居然有这么多有趣的优化。

1.经典的回溯递归解法:

#include<stdio.h>
#include<iostream>
using namespace std;
//dfs,每行只能放一个元素,遍历每行的每个位置,用一个一维数组记录,最后检查是否符合要求
int ans; int vis[10]; int abs(int x){ return x > 0 ? x : -x; } bool check(int r,int c){ for(int i = 1;i<r;i++){ if(vis[i] == c) return false; if(vis[i] - c == r - i || vis[i] - c == i - r) return false; } return true; } void dfs(int r){ if(r > 8){ ans++; return; } for(int i = 1;i<=8;i++){ if(check(r,i)){ vis[r] = i; dfs(r+1); vis[r] = 0; } } } main(){ dfs(1); cout<<ans<<endl; }

2.对角线检查优化

/*用三个数组记录列,左对角线,右对角线信息,每次判断该位置是否符合要求,只在符合要求位置放置元素。*/
#include <iostream>
using namespace std;
const int maxn=105;
const int mo=100;
typedef long long ll;
int a[maxn],n = 8,ans=0;
bool b[maxn],c[maxn],d[maxn];
void sou(int x){
    if(x > n){
        ans++;
        return;
    }
    for(int i = 1;i <= n;i++)if(!(b[i] || c[x+i] || d[x-i+n])){
        b[i] =c [x+i]=d[x-i+n]=true;
        a[x] = i;
        sou(x+1);
        b[i] =c [x+i] = d[x-i+n]=false;
    }
}
int main(){
    sou(1);
    cout<<ans;
}

3.位运算:

//算法思想与上一相同,改用三个int来存储信息,采用位运算提取合适位置
#include<iostream>
#include<stdio.h>
using namespace std;
int board;
int n;
int ans = 0;
void n_queen(int col,int ld,int rd){
    if(col == board){
        ans++;
        return;
    }
    int pos = board & (~(col | ld | rd));
    while(pos){
        int p = pos & (-pos);
        pos = pos - p;
        n_queen(col | p , (ld | p) << 1,(rd | p) >> 1);
    }
}
int main(){
    cin>>n;
    board = (1 << n) - 1;
    n_queen(0,0,0);
    cout<<ans<<endl;
}

4.十行内的八皇后...

https://www.zhihu.com/question/28543312

对知乎上各路大大的炫技佩服的五体投地,更改了一下上一代码,勉强也达到了十行的要求。。。

#include<iostream>
int n_queen(int col,int ld,int rd,int board){
    if(col == board) return 1;
    int tot = 0;
    for(int pos = board & (~(col | ld | rd)); pos != 0;pos -= (pos & (-pos))) tot+=n_queen(col | (pos & (-pos)) , (ld | (pos & (-pos))) << 1,(rd | (pos & (-pos))) >> 1,board);
    return tot;
}
int main(){
    std::cout<<n_queen(0,0,0,(1<<8)-1);
}

小结:断断续续研究了两天各类八皇后写法,感觉自己对位运算的运用加深了一个层次,更大的收获还是知道了自己的渺小,一个原以为十分简单的八皇后都可以衍生出这么多东西,递归的非递归的,全排列搜索的,回溯法的,甚至还有广搜版本的八皇后...,学习之路果然永无止境

posted @ 2016-11-14 17:16  绝对理性  阅读(17378)  评论(0编辑  收藏  举报