经典算法 | n皇后问题易理解算法和最高效率算法分析

经典算法值n后问题,

这题题给你一个n*n的棋盘,问你放置n个皇后共有多少种不用的放置方法,


在任意一个皇后所在位置的水平、竖直、以及45度斜线上都不能出现皇后的棋子

这是一个典型的回溯法框架,并且也是很简单的一个回溯法框架,比这个更简单的就只有字符串全排列问题了。

这题使用深度优先遍历的回溯法解决,每一行只放一个皇后,每一列只放一个皇后,如何判断某个皇后是否和前面已经放置的皇后斜线冲突呢,使用abs(a-b)==abs(c-d),ac,bd分别为参与判断的两个皇后的横纵坐标,只要这个等式成立则这两个皇后一定斜线冲突

使用一个数组存储,数组的下标表示行数,数组存储的值表示列数,通过交换数组每个值的位置就能实现n皇后问题的全排列的寻找


 

n皇后问题简单易懂算法框架:

大体思路是对于数组list的第t个位置,表示第t层,其值表示这一行的皇后所在的列数,这里假设取list[t]为这一行的列数,当取定这一行的列数后把list[t]和list[a]交换位置,那么t+1~n(n为list长度)就是表示下一层皇后可供选择的列数

如何判断list[a]是否可取呢,只需要判断llist[a]和前面已经确定的皇后位置是否斜线冲突就行了,也就是abs(a-b)==abs(c-d),ac,bd分别为参与判断的两个皇后的横纵坐标

 

public:
bool check(vector<int> list, int t)
{
      for(int i = 0; i < t; i++)
      {
            if(abs(i - t) == abs(list[i] - list[t])) return false;
      }
      returntrue;
}
void p(vector<int> list, int t,int& count)
{
      if(t == list.size()) {
            count++;return; }
      for(int i = t; i < list.size(); i++)
      {
            swap(list[i],list[t]);
            if(check(list, t)) p(list, t+1, count);
            swap(list[i],list[t]);
      }
}
int totalNQueens(int n) {
      vector<int>list(n, 0); int count = 0;
      for(int i = 0; i < list.size(); list[i] = i,i++);
      p(list,0, count);
      returncount;
}
};


下面是n皇后问题的最高效率算法:

基本思路跟上面那一个很想,不同的地方是当确定一个皇后的位置后,假设确定位置为t,则将位置t行列之和对应的flag位置设定为1,将t行列之差对应的flag位置设定为1,将t列数相同的flag设置为1,之后再找皇后的时候只需要判断flag[i]&& !flag[row + i +n] && !flag[4* n + row - i])就行了,flag[4*n +row - i])前面加上一个4*n是因为行列之和最大为4*n

 

class Solution {
public:
      inttotalNQueens(int n) {
            boolflag[5 * n] ={ false };
            int num= 0;
            dfs(num, flag, 0, n);
            returnnum;
      }
      void dfs(int& num, bool* flag, int row, int n) {
            if (row == n) {
                  ++num;
                  return;
            }
            for (int i = 0; i<n; i++) {
                  if(!flag[i]&& !flag[row + i + n] && !flag[4 * n + row - i]) {
                       flag[i] = 1;
                       flag[row + i + n] = 1;
                       flag[4 * n + row - i] = 1;
                       dfs(num, flag, row + 1, n);
                       flag[i] = 0;
                       flag[row + i + n] = 0;
                       flag[4 * n + row - i] = 0;
                  }
            }
      }
};


  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值