DP问题的深入思考(2024.11.26 )
今天把算法基础课的dp问题又全部过了一遍,打算连续练习一周的dp问题
个人总结,DP问题步骤:
- 先找状态定义(考虑怎么将答案用dp数组表示出来)
- 再找状态转移关系(思考答案这种状态怎么通过其他状态来获取)
- 然后是边界的初始化,结合具体问题
一般模板
线性DP:dp[n]代表前n个数字对应的答案是多少,在草稿纸上把dp[n]和dp[n-1]的状态标注出来,然后想想后者如何转移到前者
区间DP:第一层for枚举区间长度,第二层枚举区间左端点,第三层从左端点枚举到右端点
整数划分问题可以看做是背包问题(当前大数可以有小数组成的方案数)
数位统计类DP和昨天的思路一样
树形DP需要建个树,写一个dfs(k)函数,搜索以k为根的子树,一个二维数组代表选或者不选
函数思路
1. 如果不选父节点,那么子节点可能选也可能不选
2. 如果选父节点,那么子节点一定不选;
void dfs(int k )
{
dist[k][1] = w[k];
for(int i = h[k];i!=-1;i = ne[i])
{
int j = e[i];
dfs(j);
dist[k][1] +=dist[j][0];
dist[k][0]+=max(dist[j][0],dist[j][1]);
}
}
- 根据acwing上的导弹拦截问题(求需要多少套拦截系统),可得出结论:如果一个数列可以分成n种最长上升(下降)子序列,那么n=最长下降(上升)子序列的元素个数;