状态压缩 DP 学习笔记【入门篇】
前言
状态压缩 DP,简称状压 DP。
之前一直觉得状压特别难,学了一下,发现基本形态挺简单的。
在学习之前,你需要掌握:
- 简单 DP(如线性 DP,背包)
- 基本二进制运算:
&
运算、|
运算、 运算、左右移运算符。
什么是状压 DP
状态压缩,顾名思义,就是对当前的状态压缩。
怎么压缩呢?答案是二进制。
比如一个简单的例子:我有五个小球,依次编号
我想表达『选
很显然,对应二进制是
这个就是状压 DP。
也就是说,状态的转移(二进制转移),可以变成整数的加减(十进制加减)。
二进制运算
既然都有二进制,二进制的简单技巧肯定少不了。
二进制数 ,第 位是否为
此处
将
此时,
所以判断语句即为:if ( (x >> (n-1) & 1) == k)
。
* 在打代码时,需要注意括号。位运算优先级较为复杂,保险起见可以打括号,但必须保证可读性。
二进制数 ,修改第 位为
利用或运算求解。
将第
所以修改语句即为:x | (1 << (n-1))
。
二进制数 最低位的 改成
比如说,将
方法一:利用 x - (x&-x)
。其中的
方法二:
对于一个数
所以,x & (x-1)
就是答案。
你可能听不懂,那么举个例子。
若
容易发现,前三位进行 &
运算,不变;后三位进行 &
运算,必为
这下懂了吧!
状压 DP 思路
一般地,状态都用一个二维数组 dp[][]
表示。
第二维
这里还需要知道一个东西:
假如一共有
后半段的
令
则
两式相减得:
简化得:
大家肯定还是不理解,我们来看一道经典例题。
经典例题 - TSP 问题
题意
前置知识:
旅行商问题(Traveling salesman problem,即 TSP),是组合优化中的 NP 问题。
至今还没有多项式解法,仅有指数级做法。
具体问题如下:
有一张图(一般为无向图),保证所有点均连通。
有一个旅行商在
号点,要求他从 号点出发,访问过所有的城市并回到原点。 给定每对城市之间的距离,求出最短路。
如果用暴力,时间复杂度过高。
所以使用状压 DP 实现。
思路
首先,看图的稠密性决定使用
反正,用最短路算法,求出任意两点的最短距离。
设
我们可以枚举
接下来再枚举
我们可以大致写出有关
如果
啊这个方程写崩溃了。
最后的答案即为:
对了,不要忘记初始化
代码
给出代码。
大致讲一下这份代码的读入格式。
第一行
接下来一个
道路是单向的。
这里由于图是稠密图,所以使用
#include <iostream>
#include <cstdio>
#include <cstring>
#define INF 0x3f3f3f3f
#define N 20
using namespace std;
int n, e[N][N], dp[1<<N][N];
void Input()
{
scanf("%d", &n);
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
scanf("%d", &e[i][j]);
}
void floyd()
{
for (int k = 0; k <= n; k++)
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
e[i][j] = min(e[i][j], e[i][k] + e[k][j]);
}
void DP()
{
memset(dp, INF, sizeof(dp));
dp[0][0] = 0;
int maxn = (1 << n+1) - 1;
for (int k = 0; k <= maxn; k++)
for (int i = 0; i <= n; i++)
for (int j = 0; j <= n; j++)
if ( ((k >> j) & 1) == 0) //判断第 j 位是否为 0。
//把第 j 位改成 1。
dp[ k|(1<<j) ][j] = min(dp[ k|(1<<j) ][j], dp[k][i] + e[j][i]);
printf("%d", dp[maxn][0]);
}
int main()
{
Input();
floyd();
DP();
}
进一步思考
通过这道题目,我们发现:状压 DP 的时间复杂度一般是
由此可得,状压 DP 的适用范围不会很广,
如果
考虑到这个后,你就可以一眼知道,一道 DP 题有没有使用状压 DP 的可能性。
后记
貌似没有实战例题,以后有时间再补例题吧。
状压 DP 真的不难,希望大家努力学会!
还有大神整理的题单:link。
首发:2022-06-12 17:34:29
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现