DP入门
Posted honey-cat
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DP入门相关的知识,希望对你有一定的参考价值。
-
解决最优化问题 -- 多阶段决策
-
pull: f(x)从之前的状态得到(数据不规则,更好用)
-
push:对于每个f(x),更新f(x)可以到达的所有位置的结论
-
使用条件:
大问题可以拆成若干小问题
-
无后效性 --> 与之前状态计算过程无关(只需要结果)"未来与过去无关"
-
最优子结构
若后效性不好消除 -- dp数组加一维 -- 消除后效性
-
-
在最大可解区间中,寻找最优解(贪心将可解空间降到了最小),尽量缩小可解空间
-
DP舍弃了许多不会成为最优解的答案 -- 自带剪枝
-
大事化小,小事化了: 大问题 - 小问题 - 求解
当前状态为x,设计f(x):状态转移方程(看与那些局面有关)
DP三连:
- 我是谁? : 设计状态,表示局面
- 我从哪来? 我要到哪里去? : 设计转移
POJ: The Triangle
//三角形中,每个节点可以更新左下(i+1,j)与右下(i+1,j+1) 两个点
//每个节点可以被左上(i - 1,j - 1)和右上(i - 1,j)两点更新
pull:dp[i][j] = max(dp[i - 1][j - 1],dp[i - 1][j]) + dp[i][j];
push:dp(1,1) = w(1,1)
dp[i + 1][j] = max(dp[i + 1][j],dp[i][j] + w[i + 1][j]);
dp[i + 1][j + 1] = max(dp[i + 1][j + 1],dp[i][j] + w[i + 1][j + 1]);
//更新dp数组之后,遍历最后一行,输出最大值
记忆化搜索
- 斐波那契
int fib[N];
int cal(int idx){
if(idx == 1 || idx == 2) return 1;
if(fib[idx]) return fib[idx];
return cal(idx - 1) + cal(idx - 2);
}
- 洛谷P1464 Function
const int N = 25;
int a,b,c,f[N][N][N];
int cal(int i,int j, int k){
if(!i || !j || !k){
return 1;
}
if(f[i][j][k] != 0) return f[i][j][k];
if(a < b && b < c){
return cal(i,j,k - 1) + (i,j - 1,k -1) - cal(i,j - 1,k);
}
return cal(i - 1,j,k) + cal(i - 1,j - 1,k) + cal(i - 1,j,k -1) - cal(i -1,j -1,k -1);
}
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);
for(int i = 0; i <= 20; i++){
for(int j = 0; j <= 20; j++){
for(int k = 0; k <= 20; k++){
f[i][j][k] = cal(i,j,k);
}
}
}
while(cin >> a >> b >> c){
if(a == -1 && b == -1 && c == -1) break;
cout << "w(" << a <<", " << b << ", " << c << ") = ";
if(a <= 0 || b <= 0 || c <= 0){
cout << f[0][0][0] << endl;
}else if(a > 20 || b > 20 || c > 20) cout << f[20][20][20] << endl;
else cout << f[a][b][c] << endl;
}
return 0;
}
计数DP
- 数楼梯 -- pull型好写
- 过河卒问题 //dp(x,y) 到 x,y的路径条数
洛谷P1049 装箱问题
//滚动数组 数据值与前一层有关 -- 可大幅优化空间复杂度 -- 节省一维空间
//相当于01背包,将价值等于体积
int v,n,t,f[N];//f(x) 物品总体积为x时最大价值
int main(void){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> v >> n;
for(int i = 0; i < n; i++){
cin >> t;
for(int j = v; j >= t; j--){
f[j] = max(f[j],f[j - t] + t);
}
}
cout << v - f[v];
return 0;
}
洛谷P1048 采药
int x,y,t,m,f[N];//n时间内,最大价值
//思路同上
洛谷P1541 乌龟棋
//四种卡片,四个条件
f[i][j][k][l] = max(f[i][j][k][l],max(f[i - 1][j][k][l],max(f[i][j - 1][k][l],max(f[i][j][k - 1][l],f[i][j][k][l - 1]))))//可以不选 or 选四种卡片之一
以上是关于DP入门的主要内容,如果未能解决你的问题,请参考以下文章