经过这两天的刻苦学习,总算是稍微入门了一点状态压缩dp,这个真的不是很好学,所以我稍微一会就来发表这一篇我的心得体会吧。因为淋过雨,所以想为其他雨中挣扎的同学们撑一把伞(*^_^*)
首先会看到这一篇的人,应该也不是第一次认识这个概念,如果你是第一次看到状态压缩dp的话建议先去看看别人的教程,我这篇更倾向于大概懂一点,但又没完全会的状压dp教学。
首先复习一下状压dp,状压dp由于时间复杂度很大,所以是适用于数据量较小,一般n<=20的题目(这个是很关键的提示信息,看到数据量是这么小的就可以往状压dp方面考虑)
状压dp的核心在于用二进制01010101的串,利用0或者1来表示信息,所以在状压dp中会频繁地用到位运算,左移右移还有&|的操作。
下面讲讲我对状压dp的核心理解:状压dp首先名字带了个dp,所以肯定有dp的特点,也就是状态转移,递推。又因为状压用二进制压缩情况,所以转移方程就是一个二进制情况转移到相邻的二进制情况,一般情况下是开一个二维数组f[i][j],其中一个代表总的点数量n,另一个代表此时的二进制串状态,所以这一维的大小要开1<<n,也就是f[n][1<<n](具体这两个顺序看个人习惯,没什么影响)
单单这么讲还是有点抽象,下面我拿状压dp的经典例题作为例子具体讲一讲。
题目描述:
房间里放着 n 块奶酪(1<=n<=15)。一只小老鼠要把它们都吃掉,问至少要跑多少距离?老鼠一开始在 (0,0)(0,0) 点处。
输入格式
第一行有一个整数,表示奶酪的数量 n。
第 2到第 (n+1) 行,每行两个实数,第(i+1) 行的实数分别表示第 i 块奶酪的横纵坐标 xi,yi。
输出格式
输出一行一个实数,表示要跑的最少距离,保留 2 位小数。
输入样例:
4 1 1 1 -1 -1 1 -1 -1
输出样例:
7.41
有许多点,问跑完这些点需要的最少时间, 这种类型的题算是状压dp的模板题,是典型要用状压解决的例子,n的范围最大到15也符合我上面说的情况。接下来就先来分析这种题应该怎么处理。
首先,要用二进制表示情况,很容易想到,把每个奶酪当成二进制的一位,0代表还没到达这个点,1代表已经到达了这个点。那么状态转移的过程就是从某种到达情况,转移到比这种情况多一个1新到达一个点的情况,加上这两个点之间的距离。这里因为涉及到距离,所以一般会先预处理一下,求出任意两个点之间的距离储存在数组中。
其实这种题的状压dp思路很明确,但据我个人经验所言,难在代码实现,就是思想方法都懂,但是不知道怎么用代码表示,个人建议可以先照着下面的代码看一行打一行,可以慢慢熟悉起来,千万别硬着头皮光看代码不动手!
#include<bits/stdc++.h>
#define ll long long
#define db double
#define pii pair<int,int>
using namespace std;
const int maxn = 1 << 16;
db f[17][1 << 17];//当前到第i个奶酪,并且已经经过的状态为j
db d[17][17];
db x[17] = {0}, y[17] = { 0 };
ll read() {
ll x = 0, f = 0, ch = getchar();
while (!isdigit(ch)) { if (ch == '-')f = 1;ch = getchar(); }
while (isdigit(ch)) { x = x * 10 + ch - '0';ch = getchar(); }
return f ? -x : x;
}
db dis(int i, int j) {

文章介绍了状态压缩动态规划的概念,强调其适用于数据量较小的问题,并通过《吃奶酪》的经典例题详细讲解了如何运用位运算进行状态转移。作者分享了代码实现过程,包括初始化、状态转移方程和找答案的步骤,并提醒注意位运算的优先级。文章还讨论了另一道类似问题,引入了速度变化的因素,进一步加深对状态压缩DP的理解。
最低0.47元/天 解锁文章
670

被折叠的 条评论
为什么被折叠?



