没有合适的资源?快使用搜索试试~ 我知道了~
首页状压dp经典问题及代码
资源详情
资源推荐
![](https://csdnimg.cn/release/download_crawler_static/10380464/bg1.jpg)
1 / 18
动态规划本来就很抽象,状态的设定和状态的转移都不好把握,而状态压缩
的动态规划解决的就是那种状态很多,不容易用一般的方法表示的动态规划
问题,这个就更加的难于把握了。
难点在于以下几个方面:状态怎么压缩?压缩后怎么表示?怎么转移?是否
具有最优子结构?是否满足后效性?涉及到一些位运算的操作,虽然比较抽
象,但本质还是动态规划。
找准动态规划几个方面的问题,深刻理解动态规划的原理,开动脑筋思考问
题。这才是掌握动态规划的关键。
动态规划最关键的要处理的问题就是位运算的操作,容易出错,状态的设计
也直接决定了程序的效率,或者代码长短。
状态转移方程一定要仔细推敲,不可一带而过,要思考为什么这么做,掌握
一个套路,遇见这类问题能快速的识别出问题的本质,找出状态转移方程和
DP 的边界条件。
下面是一些关于状态压缩 DP 的题目,大都不难。状压 DP 的东西还有很多,
还会接着总结。
【POJ3254】Corn Fields
【题目大意】一个矩阵里有很多格子,每个格子有两种状态,可以放牧和不
可以放牧,可以放牧用 1 表示,否则用 0 表示,在这块牧场放牛,要求两个
相邻的方格不能同时放牛,即牛与牛不能相邻。问有多少种放牛方案(一头牛
都不放也是一种方案)
【解析】根据题意,把每一行的状态用二进制的数表示,0 代表不在这块放牛,
1 表示在这一块放牛。首先很容易看到,每一行的状态要符合牧场的硬件条件,
即牛必须放在能放牧的方格上。这样就能排除一些状态。另外,牛与牛之间
不能相邻,这样就要求每一行中不能存在两个相邻的 1,这样也能排除很多状
态。然后就是根据上一行的状态转移到当前行的状态的问题了。必须符合不
能有两个 1 在同一列(两只牛也不能竖着相邻)的条件。这样也能去掉一些
状态。然后,上一行的所有符合条件的状态的总的方案数就是当前行该状态
的方案数。
【状态表示】dp[state][i]:在状态为 state 时,到第 i 行符合条件的可以放牛
的方案数
【状态转移方程】dp[state][i] =Sigma dp[state'][i-1] (state'为符合条件的
所有状态)
【DP 边界条件】首行放牛的方案数 dp[state][1] =1(state 符合条件) OR 0
(state 不符合条件)
【代码】
#include <cstdio>
#include <cstring>
using namespace std;
#define mod 100000000
int M,N,top = 0;
int state[600],num[110];
int dp[20][600];
int cur[20];
inline bool ok(int x){
if(x&x<<1)return 0;
![](https://csdnimg.cn/release/download_crawler_static/10380464/bg2.jpg)
2 / 18
return 1;
}
void init(){
top = 0;
int total = 1 << N;
for(int i = 0; i < total; ++i){
if(ok(i))state[++top] = i;
}
}
inline bool fit(int x,int k){
if(x&cur[k])return 0;
return 1;
}
inline int jcount(int x){
int cnt=0;
while(x){
cnt++;
x&=(x-1);
}
return cnt;
}
int main(){
while(scanf("%d%d",&M,&N)!= EOF){
init();
memset(dp,0,sizeof(dp));
for(int i = 1; i <= M; ++i){
cur[i] = 0;
int num;
for(int j = 1; j <= N; ++j){
scanf("%d",&num);
if(num == 0)cur[i] +=(1<<(N-j));
}
}
for(int i = 1;i <= top;i++){
if(fit(state[i],1)){
dp[1][i] = 1;
![](https://csdnimg.cn/release/download_crawler_static/10380464/bg3.jpg)
3 / 18
}
}
for(int i = 2; i <= M; ++i){
for(int k = 1; k <= top; ++k){
if(!fit(state[k],i))continue;
for(int j = 1; j <= top ;++j){
if(!fit(state[j],i-1))continue;
if(state[k]&state[j])continue;
dp[i][k] = (dp[i][k] +dp[i-1][j])%mod;
}
}
}
int ans = 0;
for(int i = 1; i <= top; ++i){
ans = (ans + dp[M][i])%mod;
}
printf("%d\n",ans);
}
}
【POJ1185】炮兵阵地--经典状压 DP
【题目大意】类似于上面一道题,一个方格组成的矩阵,每个方格可以放大
炮用 0 表示,不可以放大炮用 1 表示(原题用字母),让放最多的大炮,大
炮与大炮间不会互相攻击。
【解析】可以发现,对于每一行放大炮的状态,只与它上面一行和上上一行
的状态有关,每一行用状态压缩的表示方法,0 表示不放大炮,1 表示放大炮,
同样的,先要满足硬件条件,即有的地方不能放大炮,然后就是每一行中
不能有两个 1 的距离小于 2(保证横着不互相攻击),这些要预先处理一下。
然后就是状态表示和转移的问题了,因为是和前两行的状态有关,所以要
开个三维的数组来表示状态,当前行的状态可由前两行的状态转移而来。
即如果当前行的状态符合前两行的约束条件(不和前两行的大炮互相攻
击),则当前行的最大值就是上一个状态的值加上当前状态中 1 的个数(当
前行放大炮的个数)
【状态表示】dp[i][j][k] 表示第 i 行状态为 k,第 i-1 状态为 j 时的最大炮兵个
数。
【状态转移方程】dp[i][k][t] =max(dp[i][k][t],dp[i-1][j][k]+num[t]); num[t]
为 t 状态中 1 的个数
【DP 边界条件】dp[1][1][i] =num[i] 状态 i 能够满足第一行的硬件条件(注
意:这里的 i 指的是第 i 个状态,不是一个二进制数,开一个数组保存二进制
状态)
【代码】
#include <cstdio>
![](https://csdnimg.cn/release/download_crawler_static/10380464/bg4.jpg)
4 / 18
#include <cstring>
using namespace std;
#define max(a,b) (a) > (b) ? (a) : (b)
int N,M;
char map[110][20],num[110],top;
int stk[70],cur[110];
int dp[110][70][70];
inline bool ok(int x){ //判断该状态是否合法,即不存在相邻的 1 之间的距离
小于 3 的
if(x&(x<<1)) return 0;
if(x&(x<<2)) return 0;
return 1;
}
//找到所有可能的合法状态,最多 60 种
inline void jinit()
{
top=0;
int i,total=1<<N;
for(i=0;i<total;i++) if(ok(i)) stk[++top]=i;
}
//判断状态 x 是否与第 k 行匹配
inline bool fit(int x,int k)
{
if(cur[k]&x) return 0;
return 1;
}
//数一个整型数 x 的二进制中 1 的个数(用于初始化)
inline int jcount(int x){
int cnt=0;
while(x){
cnt++;
x&=(x-1);
}
return cnt;
}
int main(){
while(scanf("%d%d",&M,&N) != EOF){
剩余17页未读,继续阅读
![ppt](https://img-home.csdnimg.cn/images/20210720083527.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://csdnimg.cn/download_wenku/file_type_ask_c1.png)
![](https://profile-avatar.csdnimg.cn/c3ceac85139e450eba4becc0ca416669_acmer_qj.jpg!1)
Star77777
- 粉丝: 99
- 资源: 5
上传资源 快速赚钱
我的内容管理 收起
我的资源 快来上传第一个资源
我的收益
登录查看自己的收益我的积分 登录查看自己的积分
我的C币 登录后查看C币余额
我的收藏
我的下载
下载帮助
![](https://csdnimg.cn/release/wenkucmsfe/public/img/voice.245cc511.png)
会员权益专享
最新资源
- 京瓷TASKalfa系列维修手册:安全与操作指南
- 小波变换在视频压缩中的应用
- Microsoft OfficeXP详解:WordXP、ExcelXP和PowerPointXP
- 雀巢在线媒介投放策划:门户网站与广告效果分析
- 用友NC-V56供应链功能升级详解(84页)
- 计算机病毒与防御策略探索
- 企业网NAT技术实践:2022年部署互联网出口策略
- 软件测试面试必备:概念、原则与常见问题解析
- 2022年Windows IIS服务器内外网配置详解与Serv-U FTP服务器安装
- 中国联通:企业级ICT转型与创新实践
- C#图形图像编程深入解析:GDI+与多媒体应用
- Xilinx AXI Interconnect v2.1用户指南
- DIY编程电缆全攻略:接口类型与自制指南
- 电脑维护与硬盘数据恢复指南
- 计算机网络技术专业剖析:人才培养与改革
- 量化多因子指数增强策略:微观视角的实证分析
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
![](https://img-home.csdnimg.cn/images/20220527035711.png)
![](https://img-home.csdnimg.cn/images/20220527035711.png)
![](https://img-home.csdnimg.cn/images/20220527035111.png)
安全验证
文档复制为VIP权益,开通VIP直接复制
![](https://csdnimg.cn/release/wenkucmsfe/public/img/green-success.6a4acb44.png)