洛谷P1216 贪心法与动态规划的选择

博客探讨了如何使用动态规划解决寻找数字三角形中最大路径的问题。贪心法虽然直观但无法保证全局最优,而动态规划通过状态转移方程能有效找到最优解。代码示例展示了如何从最后一排向上计算每个节点的最大路径,最终得出起点到终点的最优路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

洛谷P1216——动态规划

洛谷P1216上
洛谷P1216下

题目解析

在面对这样的数字三角时,我们可能会想到的有的有两种方式解决这个问题,这里我们要去找到的是最大的路径,得到的将会是最优的决策,也就是全局最优。
当看到全局最优我们可能会想到的就有两种方法。

一、贪心法

当我们想要推出全局最优,使用贪心法,首先就要做出每一个小决策的最优方式,把大的问题简化为多个小问题,通过局部最优决策推导出全局最优决策。
这里的小问题,就是在做出每一次决策如何选择的问题,也就是当前m[i][j]的决策,是选择m[i+1][j]还是m[i+1][j+1]的问题,既然是最大,那么我们肯定是选择两个决策中较大的,然后再将当前的值相加。
推导过程:7——>8——>1——>7——>5 结果:28 可以看出每一个决策都是选择所谓最优的,但是得到的结果并不是全局最优。最优的应该是题目给出的路径,通过举反例,可以看出贪心法,并不能推导出全局最优,但是也差不多。
总结:再使用贪心法是,判断能否实现目标效果,通过举反例(其中一种方式)方法,便可分遍出是否可行,很显然,这里并不能得到我们想要的结果。

二、动态规划

在使用动态规划时,首先我们需要找到的是:状态转移方程,每一个节点的就是一个状态,在这里,可以通过逆序的方式在找到转移方程。注意:需要从倒数第二排开始进行计算。
状态转移方程:dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+m[i][j];
dp中的每一个节点都是一个状态,得到的是m[i][j]+m[i+1][j] 与 m[]i[j]+m[i+1][j+1]中较大的值,与贪心法不同的是,先算出结果,在来做决策,所以,每一个节点的值,就是以当前位置向下的最大路径,最终的结果直接输出目标节点的状态值就好了。

实现方法

首先要想到最后一排节点的最大路径,很显然其实就是他本身了,所以最后一排不用算,直接将m中的最后一排赋值给dp最后一排就好了;


	for(int i=1;i<=n;i++){
		dp[n][i]=m[n][i];
	}
	

既然最后一排的最大路径已经得到,那么接下来直接从n-1排开始计算,调用转移方程:dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+m[i][j];
在计算当前节点时,计算的是结果最优路径,因为最后一排的值已经是最优路径了,所以,m[i][j]节点要加上的是结果最优路径,要加的是dp中的[i+1][j] [i+1][j+1]中最大的哪一个结果,从而得到的就是最优路径。


for(int i=n-1;i>=1;i--){//从n-1排开始计算
		for(int j=1;j<=i;j++){//第i排的第j个元素
			dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+m[i][j];//求这个节点的最大路径
		}
	}
	

dp中每个节点的状态
dp中每一个节点最大路径

最后直接输出目标节点


cout<<dp[1][1]//目标节点就是从最上方,走到最下方的最优路径

完整代码

#include<iostream>
#include<algorithm>
using namespace std;
#define M 1050 
int n;//n表示n行n列
int m[M][M]; //最大的矩阵,并不会全部使用到 
int dp[M][M]; 
//输入函数 
//注意这里的输入并不是需要完全输入,只需要输入一个三角就是 
void test(int n){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			cin>>m[i][j];
		}
	}
}
//输出函数 在程序中可以不用,这里用作验证dp中所有节点状态,或调试m中能否正确输入
void print(int n){
	for(int i=1;i<=n;i++){
		for(int j=1;j<=i;j++){
			cout<<dp[i][j]<<" ";
		}
		cout<<endl;
	}
} 
int main(){
	cin>>n;
	test(n);
	for(int i=1;i<=n;i++){
		dp[n][i]=m[n][i];
	}
	for(int i=n-1;i>=1;i--){
		for(int j=1;j<=i;j++){
			dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+m[i][j];
		}
	}
	cout<<dp[1][1];
	
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

给包番茄酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值