• 试题 算法训练 王、后传说 -> n皇后经典问题 dfs


    问题描述
      地球人都知道,在国际象棋中,后如同太阳,光芒四射,威风八面,它能控制横、坚、斜线位置。
      看过清宫戏的中国人都知道,后宫乃步步惊心的险恶之地。各皇后都有自己的势力范围,但也总能找到相安无事的办法。
      所有中国人都知道,皇权神圣,伴君如伴虎,触龙颜者死......
      现在有一个n*n的皇宫,国王占据他所在位置及周围的共9个格子,这些格子皇后不能使用(如果国王在王宫的边上,占用的格子可能不到9个)。当然,皇后也不会攻击国王。
      现在知道了国王的位置(x,y)(国王位于第x行第y列,x,y的起始行和列为1),请问,有多少种方案放置n个皇后,使她们不能互相攻击。
    输入格式
      一行,三个整数,皇宫的规模及表示国王的位置
    输出格式
      一个整数,表示放置n个皇后的方案数
    样例输入
      8 2 2
    样例输出
      10
    数据规模和约定
      n<=12
    思路:这是一道非常经典的n皇后问题 回想起三个月前被这道题支配的恐惧...
       当时理解的根本不算透彻,这次要争取把之前给留下的坑补上
       法1:
         因为已知同一行或者同一列 只能放一个皇后,我们可以从行开始看 枚举每一行开始搜
         判断这一行中的格子的列、对角线、副对角线是否可以放,类似全排列问题 复杂度O(n!)
         关于对角线: 这里我们dfs时u为行,对应坐标系中的x
                在dfs中枚举每一列i,这里的i对应坐标系中的y
                正对角线(dg),在数学中可以等价于y=x+b,即 b=y-x;  (这里为什么把截距b提出来,因为正是b来表示y与x的关系,即表示对角线关系
                副对角线(udg),同理可以化为y=-x+b,即b=y+x
                注意,由于正对角线由y-x表示的b 对于n行n列的图来说,会有负数 这里我们将b=y-x+n即可
         画个图方便理解一下
          
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <stack>
    #include <cstring>
    #include <iomanip>
    #include <cmath>
    
    using namespace std;
    
    const int N = 25;
    
    int n, ans;
    bool g[N][N];
    int col[N], dg[N], udg[N]; // 分别表示每列、正对角线、副对角线
    
    void init(int a, int b) // 预处理国王对应的9个坐标
    {
        for (int i = -1; i <= 1; i ++ )
            for (int j = -1; j <= 1; j ++ )
                g[a + i][b + j] = true;
    }
    
    void dfs(int u) // 搜索到第u行
    {
        if (u == n + 1)
        {
            ans ++ ;
            return ;
        }
        for (int i = 1; i <= n; i ++ ) // 枚举每一列是否选取
        {
            if (!col[i] && !dg[i - u + n] && !udg[u + i] && !g[u][i]) // 如果u行i列可以放的话
            {
                g[u][i] = col[i] = dg[i - u + n] = udg[u + i] = true;
                dfs(u + 1); // 搜下一行
                g[u][i] = col[i] = dg[i - u + n] = udg[u + i] = false; // 恢复现场
            }
        }
    }
    
    int main()
    {
        int a, b;
        cin >> n >> a >> b;
        init(a, b);
        dfs(1); // 从第一行开始搜索
        cout << ans << endl;
        return 0;
    }

      法2:原始的搜索方法 选或者不选

          这种方法是将棋盘每个格子遍历一遍 分别计算选和不选

          但这种方法复杂度为O(2的n^2) 样例 大概n=10以上就跑不动了 所以了解一下 明白原始的思路即可

          

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <stack>
    #include <cstring>
    #include <iomanip>
    #include <cmath>
    
    using namespace std;
    
    const int N = 25;
    
    int n, ans;
    bool g[N][N];
    int row[N], col[N], dg[N], udg[N]; // 分别表示每行、每列、正对角线、副对角线
    
    void init(int a, int b) // 预处理国王对应的9个坐标
    {
        for (int i = -1; i <= 1; i ++ )
            for (int j = -1; j <= 1; j ++ )
                g[a + i][b + j] = true;
    }
    
    void dfs(int x, int y, int s)
    {
        if (y == n + 1) y = 1, x ++ ; 
        
        if (x == n + 1)
        {
            if (s == n)
                ans ++ ;
            return ;
        }
        
        // 不放皇后
        dfs(x, y + 1, s);
        
        // 放皇后
        if (!row[x] && !col[y] && !dg[y - x + n] && !udg[x + y] && !g[x][y])
        {
            row[x] = col[y] = dg[y - x + n] = udg[x + y] = g[x][y] = true;
            dfs(x, y + 1, s + 1);
            row[x] = col[y] = dg[y - x + n] = udg[x + y] = g[x][y] = false;
        }
    }
    
    int main()
    {
        int a, b;
        cin >> n >> a >> b;
        init(a, b);
        dfs(1, 1, 0); // 从第一行第一列开始搜索
        cout << ans << endl;
        return 0;
    }
  • 相关阅读:
    struts2增删改查---layer---iframe层---通配符---国际化
    struts2增删改查---layer---iframe层
    struts2相关简单介绍
    直接在数据库客户端插入当前时间
    STL find() ,还是挺重要的
    两种应该掌握的排序方法--------1.shell Sort
    程序员的工具箱
    计算机科学中最重要的32个算法
    函数的重载与 泛型(generic)有什么不同?
    ruby编程语言-学习笔记5(第5章 语句和控制结构)
  • 原文地址:https://www.cnblogs.com/zbx2000/p/12753661.html
Copyright © 2020-2023  润新知