• n皇后问题


    一个n*n的国际象棋棋盘上放置n个皇后,这n个皇后两两均不在同一行、同一列、同一对角线上,求合法的方案数。

    需要一层一层的搜索,因此采用深度优先搜索思想。

    思考:n*n棋盘可用二维数组表示。已知约束条件:皇后均不在同一行、同一列、同一对角线上。

    故编码寻找数学关系表达式。

    解题一:考虑到每行只能放一个皇后,每列一个皇后,如果将每列皇后的行号依次写出,可以构成1~n的全排列。

    只需要求解符合要求的全排列的方案数即可。枚举所有方案,然后判断每种情况是否合法,属于朴素算法,即暴力搜索。

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 
     4 int n,ans=0;
     5 bool flag=true;   //标记这一组全排列是否可行
     6 int num[1010]={0}; //num[i]表示第i行皇后所在第几列
     7 int vis[1010]={0}; //判断数字是否用过
     8 
     9 void dfs(int y){ //参数y表示第y层
    10 
    11     //搜完一组全排列方案
    12     flag=true;  //初始化为true
    13     if(y==n+1){
    14         //num[i]两两比较,只需判断不同皇后是否在同一对角线即可,
    15         //全排列已经保证了皇后的不同行不同列
    16         for(int i=1;i<=n;i++){
    17             for(int j=i+1;j<=n;j++){
    18                 if(abs(num[i]-num[j])==abs(i-j)){
    19                     flag=false;
    20                 }
    21             }
    22         }
    23         if(flag){
    24             ans++;
    25         }
    26         return;
    27     }
    28     //全排列递归部分
    29     for(int i=1;i<=n;i++){
    30         //判断数字是否使用过
    31         if(!vis[i]){
    32             vis[i]=true;  //标记这一层深搜时数字i已使用
    33             num[y]=i;     //第y层使用数字i
    34             dfs(y+1);     //进行下一层搜索
    35             vis[i]=false;  //递归返回时清除本层标记,将数字i置为未使用
    36         }
    37     }
    38 }
    39 int main()
    40 {
    41     cin>>n;
    42     dfs(1);
    43     cout<<ans<<endl;
    44     return 0;
    45 }

    优化一:当放置一部分皇后时,可能剩余的皇后无论怎样放置都不合法,因此就没必要向下递归了,直接返回上层即可。一般来说,如果在到达递归边界前的某层,由于一些事实导致已经不需要任何一个子问题递归,就可以直接返回上一层。一般把这种方法成为回溯法。

    #include<bits/stdc++.h>
    using namespace std;

    int n,ans=0;
    bool flag=true;   //标记这一组全排列是否可行
    int num[1010]={0}; //num[i]表示第i行皇后所在第几列
    int vis[1010]={0}; //判断数字是否用过

    void dfs(int y){ //参数y表示第y层

        //搜完一组全排列方案
        flag=true;  //初始化为true
        if(y==n+1){
            //num[i]两两比较,只需判断不同皇后是否在同一对角线即可,
            //全排列已经保证了不同行不同列
            for(int i=1;i<=n;i++){
                for(int j=1;j<=n;j++){
                    if(abs(num[i]-num[j])==abs(i-j) && i!=j){
                        flag=false;
                    }
                }
            }
            if(flag){
                ans++;
            }
            return;
        }
        //全排列递归部分
        for(int i=1;i<=n;i++){
            //判断数字是否使用过
            if(!vis[i]){
                vis[i]=true;  //标记这一层深搜时数字i已使用
                num[y]=i;     //第y层使用数字i
                dfs(y+1);     //进行下一层搜索
                vis[i]=false;  //递归返回时清楚本层标记,将数字i置为未使用
            }
        }
    }
    int main()
    {
        cin>>n;
        dfs(1);
        cout<<ans<<endl;
        return 0;
    }

  • 相关阅读:
    Java NIO系列教程(九) ServerSocketChannel
    Java NIO系列教程(十) Java NIO DatagramChannel
    Java NIO系列教程(七) FileChannel
    Java NIO系列教程(八) SocketChannel
    Java NIO系列教程(六) Selector
    Java NIO系列教程(四) Scatter/Gather
    简述数据库设计的范式及应用
    简述在MySQL数据库中MyISAM和InnoDB的区别
    sql语句_2
    sql语句_统计总成绩最高的前2名
  • 原文地址:https://www.cnblogs.com/mld-code-life/p/12293552.html
Copyright © 2020-2023  润新知