DP总结
Normal \(\text{dp}\)
1. 区间
思路
枚举长度、起点、终点。
板子
样题:石子合并
for(int len = 2; len <= n; len++)//枚举长度
for(int i = 1; i+len-1 <= n; i++){//枚举起点
int j = i+len-1;//算出终点
d[i][j] = inf;//若求最小值,建议在此处初始化,避免不明错误。
for(int k = i; k < j; k++){
d[i][j] = min(d[i][k], d[k+1][j]);//最大最小值等dp操作
}
}
2. 分组
思路
设置 \(d[n]\) 数组,为前 \(n\) 个数据分组结果的最大最小值等。
板子
样题:任务安排
for(int i = 1; i <= n; i++){
d[i] = inf;//初始化最小值
for(int j = 1; j <= i; j++){//枚举上一组(起点)
d[i] = min(d[i], d[j-1] + s*(f[n] - f[j-1]) + t[i]*(f[i] - f[j-1]));
}
}
3. 状压
思路
优雅的暴力——使用二进制(有的题目可能涉及到3维4维)储存状态
以 \(d[state]\) 存储 \(d_{k_1}+d_{k_2}+d_{k_3}+···+d_{k_n}\)
例如:开关灯中, \(d[101101100(二进制)]\) 可存储1号、3号、4号、6号、7号(二进制中是1的位置)的灯被打开时的状态
板子
样题:摩天大厦里的奶牛
memset(d, 63, sizeof(d));
g[0] = w; d[0] = 1;//初始化
for(int i = 0; i <= (1<<n)-1; i++){//枚举状态
for(int j = 1; j <= n; j++){
int now = (i | 1<<(j-1));
if(i & 1<<(j-1)) continue;
if(g[i] >= a[j] && d[now] >= d[i]){
d[now] = d[i];
g[now] = max(g[now], g[i] - a[j]);
}
else if(g[i] < a[j] && d[now] >= d[i]+1){
d[now] = d[i] + 1;
g[now] = max(g[now], w - a[j]);
}
}
}
4. 背包
背包问题属于 \(\text{dp}\) 入门题型,老生常谈了,在此分享一道有趣的题目。
思路
背包问题主要是设置 \(d[c]\),用容量进行枚举。
题目(板子)
题面:奶牛展览G
\(0/1\) 背包变形,有两个量,选择其一作为容量进行 \(\text{dp}\) 。
memset(d, -63, sizeof(d));
d[400000] = 0;//因为有负数,所以开两倍数组容量进行正负数处理
for(int i = 1; i <= n; i++){
if(f[i] >= 0)//正
for(int j = 800000; j >= f[i]; j--){
d[j] = max(d[j], d[j-f[i]] + s[i]);
}
else //负
for(int j = 0; j <= 800000+f[i]; j++){
d[j] = max(d[j], d[j-f[i]] + s[i]);
}
}
树形 \(\text{dp}\)
1. 基础
思路
设置一个 \(d[n][k]\) 的 \(\text{dp}\) 数组,数组中存储本身及其子树的最大最小值等,\(k\) 用于分情况。
板子
样题:没有上司的舞会
void dfs(int x){
d[x][1] = r[x];//题目情况需求
for(int i = first[x]; i; i = a[i].Next){
int To = a[i].to;
dfs(To);//深度优先先走到底
d[x][0] += max(d[To][1], d[To][0]);
d[x][1] += d[To][0];//最大最小值等dp操作
}
}
2. 背包
思路
用背包问题的思想在树上选择点进行 \(\text{dp}\) 。
板子
样题:有线电视网
void dfs(int x){
if(x > n-m){ //题目情况需求
d[x][1] = v[x];
sz[x] = 1;
return ;
}
for(int i = first[x]; i; i = a[i].Next){ //枚举组==树的遍历
int To = a[i].to;
dfs(To);
sz[x] += sz[To];
for(int j = sz[x]; j > 0; j--){ //枚举"背包容量"
for(int l = 1; l <= sz[To] && l <= j; l++){ //枚举选择的"物品"(点)
d[x][j] = max(d[x][j], d[x][j-l] + d[To][l] - a[i].c);
}
}
}
}

浙公网安备 33010602011771号