• 2n皇后问题【dfs】


    <题目链接>

    题目描述
    给定一个n*n的棋盘,棋盘中有一些位置不能放皇后。现在要向棋盘中放入n个黑皇后和n个白皇后,使任意的两个黑皇后都不在同一行、同一列或同一条对角线上,任意的两个白皇后都不在同一行、同一列或同一条对角线上。问总共有多少种放法?n小于等于8。 

    输入
    输入的第一行为一个整数n,表示棋盘的大小。 
    接下来n行,每行n个0或1的整数,如果一个整数为1,表示对应的位置可以放皇后,如果一个整数为0,表示对应的位置不可以放皇后。 
    输出
    输出一个整数,表示总共有多少种放法。 
    样例输入
    4 
    1  1  1  1 
    1  1  1  1 
    1  1  1  1 
    1  1  1  1 
    样例输出
      2
    解题分析:
    此题与n皇后问题十分类似,也是利用递归回溯求解,因为每行只能放一个白皇后,所以可以用一维数组记录皇后所放的位置,如 qw[x]=i,表明白皇后放在第x行第i列(黑皇后类似)。这题放2n个皇后,我采取的做法是,先放n个黑皇后,再放n个白皇后,具体实现见代码,一些细节方面我都标注出来了,并且做了详细解释。
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <cmath>
     4 
     5 #define clr(a,b) memset(a,b,sizeof(a))
     6 int n,ans;
     7 int map[10][10];
     8 int qw[10],qb[10];     //白、黑皇后对应行所在的列数 
     9 int vis[10][10];
    10 bool juge(int x,int cal[]){
    11     if(!map[x][cal[x]]||vis[x][cal[x]])return false;       //如果该点为0或者已经有皇后,则不能放 
    12     for(int i=1;i<x;i++){
    13         if(cal[i]==cal[x]||(abs(i-x)==abs(cal[i]-cal[x])))return false;       //与之前放的同色皇后不在同一列,不在同一对角线 
    14     }
    15     return true;
    16 }
    17 void init(){
    18     ans=0;
    19     clr(vis,0);clr(qw,0);clr(qb,0);
    20 }
    21 void dfs_w(int x){        //放白皇后 
    22     if(x==n+1){
    23         ans++;
    24         return;
    25     }
    26     for(int i=1;i<=n;i++){
    27         qw[x]=i;
    28         if(juge(x,qw)){
    29             vis[x][i]=1;
    30             dfs_w(x+1);
    31             vis[x][i]=0;
    32         }
    33     }
    34 }
    35 void dfs_b(int x){       //放黑皇后
    36     if(x==n+1){        //这里只用判断是不是到达第n+1行就能判断是否放了n个黑皇后,不用另外用一个变量记录放的黑皇后的数量 
    37         dfs_w(1);     //因为如果某一行没有放黑皇后,那么它根本就不能够向下一行搜索 
    38         return;
    39     }
    40     for(int i=1;i<=n;i++){
    41         qb[x]=i;           //这里先放皇后再判断也是没问题的,因为如果放了皇后之后,发现不符合,这也没关系,因为qb[x]的值会被下一个循环 
    42         if(juge(x,qb)){    //的i值所覆盖。即使是循环的最后一个值不符合也没有关系,因为如果循环最后一个i不符合的话,那么它根本不会向下递归 
    43             vis[x][i]=1;   //也就自然不会对结果造成影响 
    44             dfs_b(x+1);
    45             vis[x][i]=0;
    46         }
    47     }
    48 }
    49 int main(){
    50     init();
    51     scanf("%d",&n);
    52     for(int i=1;i<=n;i++)
    53         for(int j=1;j<=n;j++)
    54             scanf("%d",&map[i][j]);
    55     dfs_b(1);
    56     printf("%d
    ",ans);
    57     return 0;
    58 }



    2018-08-26
  • 相关阅读:
    源码探索笔记:ArrayList和LinkedList的源码
    Java多线程学习总结:初窥门径
    设计模式学习总结:责任链模式
    踩坑日记:行之Blog微信小程序开发过程中碰到的问题及处理方案(持续更新...)
    初识设计模式之模板方法模式
    初识设计模式之装饰者模式
    初识设计模式之建造者模式
    初识设计模式之适配器模式
    初始设计模式之原型模式
    初识设计模式之单例模式
  • 原文地址:https://www.cnblogs.com/00isok/p/9536689.html
Copyright © 2020-2023  润新知