## 一.知识
1.我们知道计算机中数据由二进制数存储,一个二进制数的一位就是计算机中数据的最小单位bit,我们有一种运算符可直接对二进制数进行位运算,所以它的速度很快。

2.C++中的位运算符有6

        &     与运算        同1得1
        |       或运算       有1得1   
        ^      异或运算    不同得1
        ~      非运算       取反
       >>     右移运算   
      <<      左移运算

3. 按位取反举例
补码的补码就是原码,在计算机中存储全是补码,
十进制数1的二进制补码为:00000001
取反后补码为:11111110
求这个补码的原码:10000010(屏幕上显示都是原码-2)
所以1取反后等于-2

4. 在补码下,每个数值都有唯一的表示方式,并且任意两个数值做加减法运算,都等价于在32位补码下做**最高位不进位**的二进制加减法运算。发生算术溢出时,相当于自动对2^32^取模。所以要注意两个大整数相加有可能是负数。

## 二.成对变换
我们通过计算可以发现,对于非负整数n:
当n为偶数时,n ^ 1 等于 n+1
当n为奇数时,n ^ 1 等于 n-1
因此0和1,2和3,4和5,这些数对都是关于异或“成对变换”,这个性质经常用于图论,可以通过异或运算获得当前边的反向边编号。但为了安全起见,最好边的编号最好从2开始。

## 三.lowbit运算
lowbit(n) 取出非负整数n在二进制表示下最低位的1以及后边的0构成的数值。
lowbit(n) = n & (~n+1) = n & -n
lowbit 是树状数组的核心操作。
lowbit 配合hash可以找到整数二进制表示下所有是1的位,所花费的时间与1的个数同级。

## 四.二进制状态压缩

二进制状态压缩,是指将一个长度为m的bool数组用一个m位二进制整数表示并存储的方法。利用下列位运算操作可以实现原bool数组中对应下标元素的存取。

操作| 运算
---|---
取出整数n在二进制表示下的第k位                          (n>>k) & 1
取出整数n在二进制表示下第0~k-1位(后k位)       n & ((1<<k)-1)
把整数n在二进制表示下的第k位取反                       n ^ (1<<k)
对整数n在二进制表示下的第k位赋值为1                 n \| (1<<k)
对整数n在二进制表示下的第k位赋值为0                 n & (~(1<<k))

这种方法运算简便,并且节省了程序运行的时间和空间。当m不大时,可以直接使用一个整数类型存储。当m较大时,可以使用若干个整数类型(int数组),也可以直接利用bitset实现。

#### 例题
给定一张n(n<=20)个点的带权无向图,点从0~n-1标号,求起点0到终点n-1的最短hamilton路径。hamilton路径的定义是从0到n-1不重不漏地经过每个点恰好一次。([洛谷1171]

扩展题目:[POJ2288 Islands and Bridges]

思路点拨: 
很容易想到一种朴素的做法,就是枚举n个点的全排列,计算路径长度,取最小值,时间复杂度为O(n*n!),可以使用状态压缩dp将其优化到O(n^2^*2^n)

在任意时刻,要表示出哪些点被走过,哪些点没有被走过,可以用一个n位二进制数,若其第i位(0<=i<n)为1,则表示第i个点已经被经过,反之未被经过。在任意时刻还需要知道当前所处的位置,因此使用F[i,j](0<=i<2^n,0<=j<n)表示点被经过的状态对应的二进制数为i,且目前处于点j时的最短路径。

初始值F[1,0],即只经过了点0(i只有第0位是1),目前处于起点0,最短路径长度为0。方便起见,将F的其他值设为极大值,目标状态为F[(1<<n)-1,n-1],即经过所有点(i的所有位都是1),处于终点n-1的最短路。

在任意时刻,有公式F[i,j]=min{F[i ^
(1<<j),k]+weight(k,j)},0<=k<n并且((i>>j)&1)=1,即当前时刻“被经过的点的状态”对应的二进制数为i,处于点j。因为j只能恰被经过1次,所以一定是刚刚经过的,故在上一时刻“被经过的点的状态”对应的二进制数的第j位应该赋值为0,也就是i^(1<<j)。另外,上一时刻所处的位置可能是i^(1<<j)中任意一个是1的位置k,从k走到j需要weight(k,j),可以考虑取所有这样的k取最小值。
int f[1<<20][20];
int main()
{
    memset(f,0x3f,sizeof f);
    f[1][0]=0;
    for(int i=1;i<(1<<n);i+=2)

    {
        for(int j=0;j<n;j++)
        {
            if(!((i >> j) & 1))
continue; //当前i状态下,根本没有走过j
            for(int k=0;k<n;k++)
            {
                if(j==k) continue;
                if(!(i>>k & 1))
continue; //上一次状态,根本没有走过k,就更不可能从k转移到j
                f[i][j]=min(f[i][j],f[i^(1<<j)][k]+weight[k][j]);
            }
        }
    }
    cout << f[(1<<n)-1][n-1];
// 所有点走完,最后停在n-1点上
}

状压dp之位运算的更多相关文章

  1. 状压DP总结

    状态压缩就是将一行的状态压成一个二进制数,这个数的二进制形式反映了这一行的情况 比如0100111的意义为:这一排的第一个数没被使用,第二个被占用了,第三四个没被占用,第五六七个被占用 我们知道位运算 ...

  2. 状压DP详解(位运算)

    前言: 状压DP是一种非常暴力的做法(有一些可以排除某些状态的除外),例如dp[S][v]中,S可以代表已经访问过的顶点的集合,v可以代表当前所在的顶点为v.S代表的就是一种状态(二进制表示),比如 ...

  3. 【POJ3254】Corn Fields 状压DP第一次

    !!!!!!! 第一次学状压DP,其实就是运用位运算来实现一些比较,挺神奇的.. 为什么要发“!!!”因为!x&y和!(x&y)..感受一下.. #include <iostre ...

  4. 【状压DP】bzoj1087 互不侵犯king

    一.题目 Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上.下.左.右,以及左上.左下.右上.右下八个方向上附近的各一个格子,共8个格子. I ...

  5. BZOJ 1087 题解【状压DP】

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3112  Solved: 1816[Submit][ ...

  6. HITOJ 2662 Pieces Assignment(状压DP)

    Pieces Assignment My Tags   (Edit)   Source : zhouguyue   Time limit : 1 sec   Memory limit : 64 M S ...

  7. FZU 1025 状压dp 摆砖块

    云峰菌曾经提到过的黄老师过去讲课时的摆砖块 那时百度了一下题目 想了想并没有想好怎么dp 就扔了 这两天想补动态规划知识 就去FZU做专题 然后又碰到了 就认真的想并且去做了 dp思想都在代码注释里 ...

  8. 状压DP

    今天稍微看了下状压DP,大概就是这样子的,最主要的就是位运算, i and (1<<k)=0 意味着i状态下没有 k : i and (1<<k)>0 意味着i状态下有 ...

  9. POJ 3254 (状压DP) Corn Fields

    基础的状压DP,因为是将状态压缩到一个整数中,所以会涉及到很多比较巧妙的位运算. 我们可以先把输入中每行的01压缩成一个整数. 判断一个状态是否有相邻1: 如果 x & (x << ...

随机推荐

  1. php7.4 更新特性

    PHP 7.4.0 Released! The PHP development team announces the immediate availability of PHP 7.4.0. This ...

  2. 第1部分 Elasticsearch基础

    一.安装 es端口:9200 kibana端口:5601 brew install elasticsearch brew install elasticsearch brew services sta ...

  3. nginx deny 封IP

    官方文档地址:http://nginx.org/en/docs/http/ngx_http_access_module.html#deny Syntax: deny address | CIDR | ...

  4. 【记录】【MySQL】拼接字符串函数 CONCAT(str1,str2)

    CONCAT(str1,str2) 就是把str1和str2拼接

  5. python:实现几种排序算法

    冒泡排序 比较相邻两个字符,如果左边大于右边,则交换位置,遍历一遍字符后,则最大的肯定在最右边:继续循环处理剩下的字符(最右边的不用再比较了,已经最大了) 代码实现: def BubbleSort(s ...

  6. LeetCode 421. 数组中两个数的最大异或值(Maximum XOR of Two Numbers in an Array) 71

    421. 数组中两个数的最大异或值 421. Maximum XOR of Two Numbers in an Array 题目描述 给定一个非空数组,数组中元素为 a0, a1, a2, - , a ...

  7. 【转帖】Spark设计理念与基本架构

    Spark设计理念与基本架构 https://www.cnblogs.com/swordfall/p/9280006.html 1.基本概念 Spark中的一些概念: RDD(resillient d ...

  8. 数论 - 同余 + BFS (Find The Multiple)

    Find The Multiple Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 16995   Accepted: 692 ...

  9. 资源对象的池化, java极简实现,close资源时,自动回收

    https://www.cnblogs.com/piepie/p/10498953.html 在java程序中对于资源,例如数据库连接,这类不能并行共享的资源对象,一般采用资源池的方式进行管理. 资源 ...

  10. Codeforces Round #603 (Div. 2) (题解)

    A. Sweet Problem (找规律) 题目链接 大致思路: 有一点瞎猜的,首先排一个序, \(a_1>a_2>a_3\) ,发现如果 \(a_1>=a_2+a_3\) ,那么 ...