一本通1258:【例9.2】数字金字塔

原题传送门

0.前言
显然,这是一道动态规划(\(DP\)的入门题,也是一道非常经典的例题。

1.思路

\(DP\)和贪心主要就不同在:\(DP\)求全局最优解,贪心求局部最优解
这道题显然不是用贪心来做,因为当前的局部最优解可以不是全局最优解

\(Solution\ 1\) . 逆推

首先输入一个三角形样的三角形

for(int i=1;i<=R;i++){
	for(int j=1;j<=i;j++){
		read(a[i][j]);
	}
}

因为是逆推,所以我们要先定义好\(dp\)数组里的最后一行的状态

for(int i=1;i<=R;i++){
	dp[R][i]=a[R][i];
}

然后是最关键的一步,求出如下的状态转移方程:\(dp[i][j]=a[i][j]+max(dp[i+1][j],dp[i+1][j+1]);\)

\(dp[i][j]\)表示当前位置到最后一行的经过所有数的总和
\(max(dp[i+1][j],dp[i+1][j+1]);\) 指向左右两个方向取较大值
这里用加号的原因是逆推
放两张图来理解一下

输入的\(a[][]\)数组

最后的\(dp[][]\)数组

\(Solution\ 2\) . 顺推
逆推完了当然也可以顺推。思路大致与上无异。
依然输入一个三角形样的三角形

for(int i=1;i<=R;i++){
	for(int j=1;j<=i;j++){
		read(a[i][j]);
	}
}

然后对三角形顶端的位置进行初始化

dp[1][1]=a[1][1];

接着还是这个关键的状态转移方程:\(dp[i][j]=a[i][j]+max(dp[i-1][j],dp[i-1][j-1]);\)
思路和上面一样,只不过是顺推,要往来时路上面进行取最大值
不过有一点不一样:顺推推出来的结果最大值不确定,所以还需要找出结果:

int res=0;
for(int i=1;i<=R;i++){
      for(int j=1;j<=i;j++){
            res=max(res,dp[i][j]);
      }
}

再放两张图
输入的\(a[][]\)数组

最后的\(dp[][]\)数组

2.代码

//逆推
#include<iostream>
#include<cstdio>
using namespace std;
inline void read(int &x){
	int f=1;
	char ch=getchar();
	x=0;
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
int R;
int a[1001][1001];
int dp[1001][1001];
int main(){
	read(R);
	for(int i=1;i<=R;i++){
		for(int j=1;j<=i;j++){
			read(a[i][j]);
		}
	}
	for(int i=1;i<=R;i++){
		dp[R][i]=a[R][i];
	}
	for(int i=R;i>=1;i--){      //从最后一行逆推
		for(int j=1;j<=i;j++){
			dp[i][j]=a[i][j]+max(dp[i+1][j],dp[i+1][j+1]);
		}
	}
	printf("%d",dp[1][1]);
	return 0;
}
//顺推
#include<iostream>
#include<cstdio>
using namespace std;
inline void read(int &x){
	int f=1;
	char ch=getchar();
	x=0;
	while(ch<'0'||ch>'9'){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		x=x*10+ch-'0';
		ch=getchar();
	}
	x*=f;
}
int R;
int a[1001][1001];
int dp[1001][1001];
int main(){
	read(R);
	for(int i=1;i<=R;i++){
		for(int j=1;j<=i;j++){
			read(a[i][j]);
		}
	}
	dp[1][1]=a[1][1];
	for(int i=1;i<=R;i++){
		for(int j=1;j<=i;j++){
			dp[i][j]=a[i][j]+max(dp[i-1][j],dp[i-1][j-1]);
		}
	}
	int res=0;
	for(int i=1;i<=R;i++){
		for(int j=1;j<=i;j++){
			res=max(res,dp[i][j]);
		}
	}
	printf("%d",res);
	return 0;
}
posted @ 2020-09-24 19:35  _pwl  阅读(813)  评论(0编辑  收藏  举报
1 2 3
4