[DP专栏]来源型DP
作者:互联网
今天,我们来聊一聊来源型DP。
比如说,这题。
虽然说是IOI1994这样好像很牛的题目,不过好像不难。
一、数字三角形
1.贪心
如果我们走贪心的话,我可以直接给你一个反例:
1
0 1
100 0 1
101 0 0 1
如果走贪心,我们会首先选择大的那边,然后走了4个1。
可是,最优走法是1->0->100->101,答案是202。
为什么贪心会错?因为他只会选择局部的最优,不会去想那一边会不会有更大的数。
贪心的问题在于:目光太短浅。
2.搜索
贪心不行的话……emm我们就爆搜。
可是!n到1000诶!你可以获得若干个TLE,而且代码还比正解长。
最主要是,你不好剪枝。
3.DP
终于请来了我们的主角——DP。
首先我们设计状态:\(f_{i,j}\)表示从第\(i\)行第\(j\)列为开头,得到的最大值。
边界:显然,\(f_{N,i}=a_{N,i}\)。最后一行的每个数得到的最大值都是自己。
状态转移方程:\(f_{i,j}=\max(f_{i+1,j},f_{i+1,j+1})+a_{i,j}\)每个数都可以从下面两个数来。
因为DP要求无后效性,所以我们从下往上计算。
最后答案就是\(f_{1,1}\)。
4.代码
#include<iostream>
using namespace std;
int a[1005][1005];
int f[1005][1005];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++) for(int j=1;j<=i;j++) cin>>a[i][j];
for(int i=n;i>=1;i--){
for(int j=1;j<=i;j++){
f[i][j]=max(f[i+1][j],f[i+1][j+1])+a[i][j];
}
}
cout<<f[1][1]<<endl;
return 0;
}
二、过河卒
题目
如果不管马的阻挡,我们单纯看这个走格子,像什么?
是不是小学的时候数格子的数学题?
是不是有技巧?
是不是每一个位置是他左边加上面?
这就是DP!
最开始\(f_{0,0}=1\),之后遍历每一个点,如果他不是第一行就加上\(f_{i-1,j}\),不是第一列就加上\(f_{i,j-1}\)。
部分代码
dp[0][0]=1;
for(int i=0;i<=n;i++){
for(int j=0;j<=m;j++){
if(d[i][j]==false){//判断是否可以走
if(i){
dp[i][j]+=dp[i-1][j];
}
if(j){
dp[i][j]+=dp[i][j-1];
}
}
}
}
cout<<dp[n][m]<<endl;
三、总结
来源型DP,就是要有明确的来源,就能做出来。
我们这期就到这了,下期再见~
标签:int,我们,专栏,100,1005,来源,DP,贪心 来源: https://www.cnblogs.com/tigerchen/p/15369520.html