标签:int 我们 专栏 100 1005 来源 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
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。