二进制状态压缩:应用及例题

1.位运算:https://www.cnblogs.com/yrjns/p/11246163.html

符号 描述 运算规则
& 两个位都为1时,结果才为1
| 两个位都为0时,结果才为0
^ 异或 两个位相同为0,相异为1
~ 取反 0变1,1变0
<< 左移 各二进位全部左移若干位,高位丢弃,低位补0
>> 右移 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移)

Tips:

(1)&与相当于求交集操作,|相当于求并集操作

(2)位运算中的& | 不同于判断条件中的与和或,也就是if中的条件句要写成a&&b 或 a||b

(3)注意运算的优先级:不知道优先级就加括号就行!优先级:https://baike.baidu.com/item/%E8%BF%90%E7%AE%97%E7%AC%A6%E4%BC%98%E5%85%88%E7%BA%A7/4752611?fr=aladdin

2.状压操作:

(1)取出整数n在二进制表示下的第k位:(n>>k)&1,将n右移k位得到第k位的数值

(2)取出整数n在二进制表示下的第0~k-1位:n&((1<<k)-1),2^k-1应当表示从0~k-1为所有都为1,高于k位表示0的数,与之and操作取出0~k-1范围内的1

(3)把整数n的第k为取反:n^(1<<k),将第k位赋成1,如果n的第k位为1,则1xor1=0,1->0,如果为0,0xor1=1,0->1;

(4)把n的第k位赋成1:n|(1<<k)强行将2^k并入n中

(5)把n的第k位赋成0:n&(~(1<<k)) 将第k位赋成0,等价于将2^k的补集与n求交集,也就是~(1<<k)与n求交集

(6)判断n中是否有连续的1:(n&(n<<1))||(n&(n>>1)) 分别左移右移判断有无真!

(7)查询n中的第i位是0or1:n&(1<<k)

(8)将n直接按为取反(保留原有的位数不变): n^=((1<<k)-1)右边的数表示从0-k-1位全为真,和n取反也就是将每一位都取反1

3.例题:最短Hamilton路径

给定一张n个节点的带权无向图,点从0到n-1编号,要求从0到n-1的最短的Hamilton路径。Hamilton路径指的是从0道n-1不重不漏地经过每一个点恰好一次

Brute_force?枚举n个点的全排列,按照给定排列尝试,复杂度:O(n*n!)

可以用状压DP压缩到O(n*2^n)

  首先,我们如何表示那些节点已经经过,而那些节点还未被经过?我们可以用一个n位的二进制数表示!对于每一位,如果为0则表示尚未经过,1则表示这一位下的节点已经经过了

在任意时刻我们还需要知道当前所在的位置,因此设f[i][j]表示当前经过路径信息为i时,当前位置到j的最短Hamilton路径。其中i∈[0,2^n-1],j∈[1,n]

  在起点0处时,初始化f[1][0]=0;对于剩下所有的状态,初始化为一个极大值,目标结果是f[2^n-1][n-1]

  我们可以得到转移方程:f[i][j]=min{f[i^(1<<j)][k]+weight(j,k)}; 其中转移前的状态必定是没有j的,然后任选一个中间节点k作为转移信息

  其中条件是:(i&(1<<j) )&& (i^(1<<j))&(1<<k) or (i>>j)&1=1 且k属于[0,n] 因为j恰好被经过一次,所以一定是有上一个没有j的状态中转移过来的,则上一个状态的j位应该被赋值为0.同时上一时刻所处的位置是

i xor (1<<j)中任意一个是1的数位k,从而推导出上式。

原文地址:https://www.cnblogs.com/little-cute-hjr/p/12289749.html

时间: 2024-07-31 18:08:42

二进制状态压缩:应用及例题的相关文章

二进制状态压缩及位运算

位运算符: 与(&),或(|),非(~), 异或(^); 移位运算: 1.左移:在二进制表示下把数字同时向左移动,低位以0填充,高位越界后舍弃 1 << n = 2^n, n << 1 = 2n 2.算术右移:在二进制补码表示下把数字同时向右移动,高位以符号位填充,低位越界后舍弃 n >> 1 = n/2.0(向下取整) eg:(-3)>> 1 = -2, 3 >> 1 = 1;  二进制状态压缩,是指将一个n位的 bool 数组用 n

# 最短Hamilton路径(二进制状态压缩)

最短Hamilton路径(二进制状态压缩) 题目描述:n个点的带权无向图,从0-n-1,求从起点0到终点n-1的最短Hamilton路径(Hamilton路径:从0-n-1不重不漏的每个点恰好进过一次) 题解:二进制状态压缩算法\(O(2^n*n^2)\),需要记录当前经过了哪些点,当前在哪个位置.\(f[i][j]\) ? \(i\)转化为二进制每一位代表是否经过该点,\(j\)表示当前位于j这个点 #include <iostream> #include <cstring> u

皮卡丘的梦想2(线段树+二进制状态压缩)

Description 一天,一只住在 501 实验室的皮卡丘决定发奋学习,成为像 LeiQ 一样的巨巨,于是他向镇上的贤者金桔请教如何才能进化成一只雷丘. 金桔告诉他需要进化石才能进化,并给了他一个地图,地图上有 n 个小镇,他需要从这些小镇中收集进化石. 接下来他会进行 q 次操作,可能是打听进化石的信息,也可能是向你询问第 l 个小镇到第 r 个小镇之间的进化石种类. 如果是打听信息,则皮卡丘会得到一个小镇的进化石变化信息,可能是引入了新的进化石,也可能是失去了全部的某种进化石. 如果是向

Sleep Buddies (二进制状态压缩)

Sleep Buddies 算法:状态压缩, 把每一个集合都压缩成一个数字. 使用方法:把每个状态都进行1<<(x-1)压缩,这样的话我们可以保证,每个二进制上代表的那个数字是1就代表存在这个属性. AC_Code 1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=1e5+10; 5 #define rep(i,first,last) for(ll i

POJ-3279.Fliptile(二进制状态压缩 + dfs) 子集生成

昨天晚上12点刷到的这个题,一开始一位是BFS,但是一直没有思路.后来推了一下发现只需要依次枚举第一行的所有翻转状态然后再对每个情况的其它田地翻转进行暴力dfs就可以,但是由于二进制压缩学的不是很透,一直有小问题,下面我还会讲子集生成的相关方法,有兴趣的同学可以继续关注. 本题大意:一块地,有黑(1)白(0)之分,牛每次踩踏使得当前块以及四连块都变色,问当牛如何踩时使得地都变白并且求出最小踩踏次数和踩踏路径的最小字典序时的踩踏地图. 本题思路:由于同一块地被翻两次都会回到原来的状态,所以只需要对

BFS+二进制状态压缩 hdu-1429

好久没写搜索题了,就当练手吧. vis[][][1025]第三个维度用来维护不同key持有状态的访问情况. 对于只有钥匙没有对应门的位置,置为'.',避免不必要的状态分支. // // main.cpp // hdu_1429 // // Created by Luke on 16/10/8. // Copyright © 2016年 Luke. All rights reserved. // #include <iostream> #include <string> #inclu

二进制状态压缩相关操作

取出整数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)) 原文地址:https://www.cnblogs.com/Mr94Kevin/p/10376623.html

Count Color (线段树区间染色?二进制状态压缩)

题目链接:https://vjudge.net/problem/POJ-2777 题意: 有L个画板,30种颜色,o个操作:P a b :询问a-b 种有多少种颜色不同的,C  a b c:把a-b全部涂成c的颜色(覆盖掉) 1 #include <stdio.h> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <string> 6 #in

HDU 3001 Travelling(状态压缩DP+三进制)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3001 题目大意:有n个城市,m条路,每条路都有一定的花费,可以从任意城市出发,每个城市不能经过两次以上,要求经过所有城市并且花费最少,求出最小花费. 解题思路:三进制的状态压缩DP,跟二进制还是有一点不一样的,因为三进制没有直接的位运算,还要自己先做处理利用num[i][j]记录数字i各位的三进制表示方便计算,其他的就跟二进制状态压缩没有太大区别了.还有注意: ①开始要将n个起点初始化,dp[bit