题目传送门 P1216 [IOI1994][USACO1.5]数字三角形 Number Triangles
这题是很多教材的DP入门题,确实,用它来练习DP对初学者来说十分容易,不过也有一些教材用来做递推的入门题
思路分析
我们来看题
我看到这题时有两个思路,第一个是递推,第二个是DP
先说递推,递推的话,我们可以倒推,从最底层出发,往上寻找最大路径,a[i][j]即为第i层第j个时的最大值,那么a[1][1]就是我们所要的答案
所以我们可以这样写
#include<iostream>
using namespace std;
int n,a[1001][1001];
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
cin>>a[i][j]; //输入金字塔
}
}
for(int i=n-1;i>=1;i--){
//注意要从第n-1层塔开始,因为从下往上选,第a[i][j]个点只能是由a[i+1][j+1]个或第a[i+1][j]往上走到达,i+1最大为n
for(int j=1;j<=i;j++){
if(a[i+1][j]>=a[i+1][j+1]) //这里就是判断哪条路大了,也可以用iostream库自带的max
a[i][j]+=a[i+1][j];
else a[i][j]+=a[i+1][j+1];
}
}
cout<<a[1][1]<<endl;
return 0;
}
终于写好了代码,然而交上去,我们会发现,只有55分…
于是我开始尝试DP(其实还可以用记忆化搜索的,各位自己尝试一下吧)
DP其实说白了就是倒着递推,我们从上往下推,找最大的路
不过由于上面递推的经验,这里需要优化一下
用一个一维数组f[i]来存放每条路的和,最后比较一下得出最大值
状态转移方程就是 f [j]=max(f[j],f[j-1])+a[i][j];
现在来看代码
#include<iostream>
using namespace std;
int n,a[1001][1001],f[1001],ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
cin>>a[i][j];
}
}
f[1]=a[1][1]; //初始化
for(int i=2;i<=n;i++){
for(int j=i;j>=1;j--){ //f数组是一维的,所以第二层就要倒着循环,原因和01背包的一维数组优化差不多
f[j]=max(f[j],f[j-1])+a[i][j];}
}
for(int i=1;i<=n;i++){
ans=(ans>f[i])?ans:f[i]; //比较出最大的
}
cout<<ans;
return 0;
}
到这里我们再提交,就可以AC了
END