状压dp之位运算
## 一.知识
1.我们知道计算机中数据由二进制数存储,一个二进制数的一位就是计算机中数据的最小单位bit,我们有一种运算符可直接对二进制数进行位运算,所以它的速度很快。
2.C++中的位运算符有6种:
| 或运算 有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之位运算的更多相关文章
- 状压DP总结
状态压缩就是将一行的状态压成一个二进制数,这个数的二进制形式反映了这一行的情况 比如0100111的意义为:这一排的第一个数没被使用,第二个被占用了,第三四个没被占用,第五六七个被占用 我们知道位运算 ...
- 状压DP详解(位运算)
前言: 状压DP是一种非常暴力的做法(有一些可以排除某些状态的除外),例如dp[S][v]中,S可以代表已经访问过的顶点的集合,v可以代表当前所在的顶点为v.S代表的就是一种状态(二进制表示),比如 ...
- 【POJ3254】Corn Fields 状压DP第一次
!!!!!!! 第一次学状压DP,其实就是运用位运算来实现一些比较,挺神奇的.. 为什么要发“!!!”因为!x&y和!(x&y)..感受一下.. #include <iostre ...
- 【状压DP】bzoj1087 互不侵犯king
一.题目 Description 在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上.下.左.右,以及左上.左下.右上.右下八个方向上附近的各一个格子,共8个格子. I ...
- BZOJ 1087 题解【状压DP】
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3112 Solved: 1816[Submit][ ...
- HITOJ 2662 Pieces Assignment(状压DP)
Pieces Assignment My Tags (Edit) Source : zhouguyue Time limit : 1 sec Memory limit : 64 M S ...
- FZU 1025 状压dp 摆砖块
云峰菌曾经提到过的黄老师过去讲课时的摆砖块 那时百度了一下题目 想了想并没有想好怎么dp 就扔了 这两天想补动态规划知识 就去FZU做专题 然后又碰到了 就认真的想并且去做了 dp思想都在代码注释里 ...
- 状压DP
今天稍微看了下状压DP,大概就是这样子的,最主要的就是位运算, i and (1<<k)=0 意味着i状态下没有 k : i and (1<<k)>0 意味着i状态下有 ...
- POJ 3254 (状压DP) Corn Fields
基础的状压DP,因为是将状态压缩到一个整数中,所以会涉及到很多比较巧妙的位运算. 我们可以先把输入中每行的01压缩成一个整数. 判断一个状态是否有相邻1: 如果 x & (x << ...
随机推荐
- php7.4 更新特性
PHP 7.4.0 Released! The PHP development team announces the immediate availability of PHP 7.4.0. This ...
- 第1部分 Elasticsearch基础
一.安装 es端口:9200 kibana端口:5601 brew install elasticsearch brew install elasticsearch brew services sta ...
- nginx deny 封IP
官方文档地址:http://nginx.org/en/docs/http/ngx_http_access_module.html#deny Syntax: deny address | CIDR | ...
- 【记录】【MySQL】拼接字符串函数 CONCAT(str1,str2)
CONCAT(str1,str2) 就是把str1和str2拼接
- python:实现几种排序算法
冒泡排序 比较相邻两个字符,如果左边大于右边,则交换位置,遍历一遍字符后,则最大的肯定在最右边:继续循环处理剩下的字符(最右边的不用再比较了,已经最大了) 代码实现: def BubbleSort(s ...
- 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 ...
- 【转帖】Spark设计理念与基本架构
Spark设计理念与基本架构 https://www.cnblogs.com/swordfall/p/9280006.html 1.基本概念 Spark中的一些概念: RDD(resillient d ...
- 数论 - 同余 + BFS (Find The Multiple)
Find The Multiple Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 16995 Accepted: 692 ...
- 资源对象的池化, java极简实现,close资源时,自动回收
https://www.cnblogs.com/piepie/p/10498953.html 在java程序中对于资源,例如数据库连接,这类不能并行共享的资源对象,一般采用资源池的方式进行管理. 资源 ...
- Codeforces Round #603 (Div. 2) (题解)
A. Sweet Problem (找规律) 题目链接 大致思路: 有一点瞎猜的,首先排一个序, \(a_1>a_2>a_3\) ,发现如果 \(a_1>=a_2+a_3\) ,那么 ...