N皇后 八皇后 位运算解法

问题描述

什么是八皇后?

题目链接

N皇后

解法

? 直接在N*N的棋盘上进行深搜,试探着下棋,也就是回溯法。

? 对于一个皇后来说,我们需要判断她的 八个方向 ,即 主对角线,副对角线,行,列

? 1. 确定状态

? 第一眼的感觉是要用 四个数组来储存情况,但时间上只需要三个 ,把 行 排除在外

? 因为每次搜索的时候,都自动按搜索,也就是变量 row ,每改变一次,代表了不同的行

? 接下来,分析主对角线 ,对于N*N的矩阵来说,主对角线上的值满足 行和列的差为定值

? 即,做减法得到的下标是唯一的,因为数组没有 负值的索引 所以要 再差值的基础上,加n

? row - col + n 得到唯一的下标,

? 副对角线 ,行 列 之和为定值 row + col

? 直接利用下标 储存就行

? 2.试探着下棋 (回溯)

? i 代表列 ,每次搜索按列递进,这样保证了每一列,只可能放一个棋子

? lvis 代表 主对角线的状态 ,rvis 代表副对角线的状态 ,col 代表 列 的状态

? if 那段表示 ,如果 主对角线,副对角线,列 上都没有棋子落下

? 之后 改变状态 ,将 主对角线,副对角线,列 都设置为 1

? dfs(row + 1) 按行递进

? dfs(row + 1)执行完之后,退回到之前的状态:

? lvis,rvis,col 都置为 0 ,在这一行中找下一个可以放的位置

for(int i=1;i<=n;++i){
        if(!lvis[i-row+8]&&!rvis[i+row]&&!col[i]){
            lvis[i-row+8] = 1;
            rvis[i+row] = 1;
            col[i] = 1;
            ans[row] = i;
            dfs(row+1);
            lvis[i-row+8] = 0;
            rvis[i+row] = 0;
            col[i] = 0;
            }
        }

1.朴素解法(回溯)

#include <bits/stdc++.h>
using namespace std;
const int N =1e2+10;
bool lvis[N],rvis[N],col[N];
int n,tot,ans[N];
void dfs(int row){
    if(row == n+1){
         tot++;
         for(int i=1;i<=8;++i){
             cout<<ans[i]<<" ";
         }
         cout<<endl;
    }
    else {
        for(int i=1;i<=n;++i){
        if(!lvis[i-row+8]&&!rvis[i+row]&&!col[i]){
            lvis[i-row+8] = 1;
            rvis[i+row] = 1;
            col[i] = 1;
            ans[row] = i;//保存棋子的位置, 第row行,第i列;
            dfs(row+1);
            lvis[i-row+8] = 0;
            rvis[i+row] = 0;
            col[i] = 0;
            }
        }
    }
}
int main(){
    //cin>>n;
    n = 8;
    dfs(1);
    cout<<tot<<endl;
    return 0;
}

2.位运算解法(状态储存方式的不同)

? 根本思路是一样的,拿位运算解,就是把原先用数组储存状态的方式,改变为用 整数 int

? 因为 一个int 占 4个字节 4*8 个bit,所以相当于 含有 32个空间的数组

? 用位运算 大大降低了占用的空间支出

? 基本位运算操作

? 对于改变状态来说,无非就两种 ,1 和 0

? 对于特定位置 1 :

    a |= (1<<i);

? 把 1 左移 i 位 ,得到一个32位整数

? 假如 i 为 2

? (省略24位前置 0) 0000 0100

? 假如 i 为 1

? (省略24位前置 0) 0000 0010

? 假如 i 为 7

? (省略24位前置 0) 1000 0000

? 将其与 a 进行 或运算 ,原先 a上的第 i 位, 将被置为 1

? 对于特定位置 0:

    a &= ~(1<<i);

? ~运算 ,把各位上的值都取反

? 假如 i 为 2

? (省略24位前置 1) 1111 1011

? 假如 i 为 1

? (省略24位前置 1) 1111 1101

? 假如 i 为 7

? (省略24位前置 1) 0111 1111

? 将其与 a 进行 与运算 ,原先 a 上的第 i 位,将被置为 0

? 判断状态

? x 的第 i 位 是否为 1

    bool getbit(int x,int i){
        return !((x>>i) & 1);
    }

? 把 x 右移 i 位(这样当前 x 的第0 位,就是原先 x 的第 i 位), 和 1进行与运算

完整代码

#include <bits/stdc++.h>
using namespace std;
const int N =1e2+10;
int lvis,rvis,col;
int n,tot,ans[N];
bool getbit(int x,int i){
    return !((x>>i) & 1);
}
void dfs(int row){
    if(row == n+1){
         tot++;
         for(int i=1;i<=8;++i){
             cout<<ans[i]<<" ";
         }
         cout<<endl;
    }
    else {
        for(int i=1;i<=n;++i){
        if(getbit(lvis,i-row+8)&&getbit(rvis,i+row)&&getbit(col,i)){
            lvis |= (1<<(i-row+8));
            rvis |= (1<<(i+row));
            col |= (1<<i);
            ans[row] = i;
            dfs(row+1);
            lvis &= ~(1<<(i-row+8));
            rvis &= ~(1<<(i+row));
            col &= ~(1<<i);
            }
        }
    }
}
int main(){
    cin>>n;
    //n = 8;
    dfs(1);
    cout<<tot<<endl;
    return 0;
}

(C++ 自带 bitset ,可以不用这么麻烦)

只要把 这行

bool lvis[N],rvis[N],col[N];

替换成这行

bitset<N> lvis,rvis,col;
#include <bits/stdc++.h>
using namespace std;
const int N =1e2+10;
bitset<N> lvis,rvis,col;
int n,tot,ans[N];
void dfs(int row){
    if(row == n+1){
         tot++;
         for(int i=1;i<=8;++i){
             cout<<ans[i]<<" ";
         }
         cout<<endl;
    }
    else {
        for(int i=1;i<=n;++i){
        if(!lvis[i-row+8]&&!rvis[i+row]&&!col[i]){
            lvis[i-row+8] = 1;
            rvis[i+row] = 1;
            col[i] = 1;
            ans[row] = i;
            dfs(row+1);
            lvis[i-row+8] = 0;
            rvis[i+row] = 0;
            col[i] = 0;
            }
        }
    }
}
int main(){
    //cin>>n;
    n = 8;
    dfs(1);
    cout<<tot<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/317zhang/p/10579916.html

时间: 2024-07-29 07:36:36

N皇后 八皇后 位运算解法的相关文章

皇后问题(DFS)(位运算)

皇后问题 题目描述: 有一个n*n的棋盘,你要在这个棋盘上放上n个皇后,使得她们不能相互攻击.当然为了使得问题更加有趣,我们在棋盘上限定了一些位置使得这些位置上不能放皇后. 输入格式: 第一行两个数n和m ,表示在一个n*n的棋盘上放n个皇后,有m个受限位置. 接下来m行每行两个数,x和y,表示第x行,第y列这个位置不可以放皇后. 输出格式: 一行一个数 ans,表示总的方案数. 样例输入: 4 1 1 2 样例输出: 1 朴素算法(60分) #include<iostream> using

N皇后问题 --使用位运算解决

关键位运算 x & (-x) 取得最低位1 x & (x-1) 去掉最低位1 class Solution(object): def totalNQueens(self, n): """ :type n: int :rtype: int """ if n < 1 : return [] self.count = 0 self.DFS(n,0,0,0,0) return self.count def DFS(self,n, r

POJ 1781 In Danger Joseph环 位运算解法

Joseph环,这次模固定是2.假设不是固定模2,那么一般时间效率是O(n).可是这次由于固定模2,那么能够利用2的特殊性,把时间效率提高到O(1). 规律能够看下图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQva2VuZGVuMjM=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" > 具体具体解析请看大师Knuth的Concrete m

P1219 八皇后 含优化 1/5

题目描述 检查一个如下的6 x 6的跳棋棋盘,有六个棋子被放置在棋盘上,使得每行.每列有且只有一个,每条对角线(包括两条主对角线的所有平行线)上至多有一个棋子. 上面的布局可以用序列2 4 6 1 3 5来描述,第i个数字表示在第i行的相应位置有一个棋子,如下: 行号 1 2 3 4 5 6 列号 2 4 6 1 3 5 这只是跳棋放置的一个解.请编一个程序找出所有跳棋放置的解.并把它们以上面的序列方法输出.解按字典顺序排列.请输出前3个解.最后一行是解的总个数. //以下的话来自usaco官方

位运算总结&amp;拾遗

JavaScript 位运算总结&拾遗 最近补充了一些位运算的知识,深感位运算的博大精深,此文作为这个系列的总结篇,在此回顾下所学的位运算知识和应用,同时也补充下前文中没有提到的一些位运算知识. 把一个数变为大于等于该数的最小的2的幂 一个数为2的幂,那么该数的二进制码只有最高位是1. 根据这个性质,我们来举个栗子,比如有数字10,转为二进制码后为: 1 0 1 0 我们只需把 0 bit的位置全部用1填充,然后再把该二进制码加1就ok了.而x | (x + 1)正好可以把最右边的0置为1,可是

N皇后(回溯版+位运算版)

题目描述 Description 在n×n格的棋盘上放置彼此不受攻击的n个皇后.按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子.n后问题等价于再n×n的棋盘上放置n个皇后,任何2个皇后不妨在同一行或同一列或同一斜线上. 输入描述 Input Description 给定棋盘的大小n (n ≤ 13) 输出描述 Output Description 输出整数表示有多少种放置方法. 样例输入 Sample Input 8 样例输出 Sample Output 92 数据范围

N皇后问题(位运算实现)

本文参考Matrix67的位运算相关的博文. 顺道列出Matrix67的位运算及其使用技巧 (一) (二) (三) (四),很不错的文章,非常值得一看. 主要就其中的N皇后问题,给出C++位运算实现版本以及注释分析. 皇后问题很经典,就不再赘述问题本身,解决皇后问题,一般采用的都是深搜DFS+回溯的方法,按照行(列)的顺序枚举每一个可以放置的情况,然后进行冲突判断,当前的放置是否合法,合法就继续搜索下一层,不合法就搜索就回溯.直到,找到一个合法的解,每一层都有一个皇后并且不发生冲突,这时候,放置

C#中八皇后问题的递归解法——N皇后

百度测试部2015年10月份的面试题之——八皇后. 八皇后问题的介绍在此.以下是用递归思想实现八皇后-N皇后. 代码如下: using System;using System.Collections.Generic; namespace QueensSolution { class Program { static int count = 0; static void Main(string[] args) { int n = Int32.Parse(Console.ReadLine()); L

八皇后解法(回溯法)

package com.company; /** * Created by Administrator on 2016/9/15. */public class EigthQueue { private static int N = 8; private int count = 0; // 总方案数 private int[] flag = {-1, -1, -1, -1, -1, -1, -1, -1}; //回溯法递归实现八皇后问题 //输出棋盘 private void printChes