zoukankan      html  css  js  c++  java
  • 八皇后问题的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);
    }

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

  • 相关阅读:
    JAVA类与对象(一)----基础概念理解
    JAVA数组
    JAVA算术运算符、关系运算符和位运算符
    JAVA数据类型
    JAVA配置环境变量
    C#中怎么生成36位的GUID
    jqAjax
    二进制1的个数
    成绩转换
    对决
  • 原文地址:https://www.cnblogs.com/xinghuan/p/6061824.html
Copyright © 2011-2022 走看看