蒜头君回家和acwing数字三角形(一类型题)

本文探讨了蒜头君从起点到终点的最短路径问题,以及如何运用动态规划解决数字三角形中路径和的最大化。通过实例和代码展示了如何处理边界条件和决策过程,以及两种不同的思考角度。

 特点:都是从一个点到另一个点,求路径的最值,而且都有边界条件,例如数字问题从上到下求f[i][j]的最值的时候,需要额外考虑左右边界情况。

例如j=1的时候,下面的数字和只能由上面的第一个推导出来(在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点),因为最左面的节点没有右下角节点,最右面的节点没有左下角节点。

1.蒜头君要回家,已知蒜头君在左下角(1,1)位置,家在右上角(n,n)坐标处。蒜头君走上一-个格子(i, j)会花费- -定的体力aij,而且蒜头君只会往家的方向走,也就是只能往上,或者往右走。蒜头君想知道他回到家需要花费的最少体力是多少。:

例如下图所示,格子中的数字代表走上该格子花费的体力:

对于该图来说,最优策略已在图上标出,最少花费体力为: 3+2 +4+3= 12。
我们把走到一个点看做一个状态,对蒜头君来说,走到一个点只有两种方式,-个是从下面走到该点,-种是从左边走到该点。那么点(i,j)要么是从(i-1,j)走到(i,j),要么是从点(i,j-1)走到(i,j)。

所以从哪个点走到(i,j)就是一个决策。接下来,我们用dp(i,j)来代表走到点(i,j)一共花费的最少体力。
我们需要花费最少力气走到家,所以可以得到状态转移方程: dp(i,j) = min(dp(i-1,j),dp(i,j-1))+ai,j。根据转移方程,我们可以推出走到每个点花费的最少体力。

但是到达边界点的时候无法进行决策 ,例如i==1时  dp[i][j] = dp[i][j - 1] + a[i][j];

j==1时   dp[i][j] = dp[i - 1][j] + a[i][j];

//蒜头君回家
#include<iostream>
#include<algorithm>
using namespace std;
int n;
int main() {
	int a[100][100];
	int dp[100][100];
	cin >> n;
	for (int i = 1; i <=n; i++) {
		for (int j = 1; j <= n; j++) {
			cin >> a[i][j];//输入走每个方格的权值
		}
	}
	dp[1][1] = 1;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			if (i == 1 && j == 1) {
				dp[i][j] = 0;
			}
			else if (i == 1) {
				dp[i][j] = dp[i][j - 1] + a[i][j];

			}
			else if (j == 1) {

				dp[i][j] = dp[i - 1][j] + a[i][j];
			}
			else {
				dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + a[i][j];
			}
			
		}
	}
	cout << "dp[n][n]: " << dp[n][n] << endl;
	return 0;
}

2..给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。

        7
      3   8
    8   1   0
  2   7   4   4
4   5   2   6   5
输入格式
第一行包含整数 n,表示数字三角形的层数。

接下来 n 行,每行包含若干整数,其中第 i 行表示数字三角形第 i 层包含的整数。

输出格式
输出一个整数,表示最大的路径数字和。

数据范围
1≤n≤500,
−10000≤三角形中的整数≤10000
输入样例:
5
7
3 8
8 1 0 
2 7 4 4
4 5 2 6 5
输出样例:
30

 代码:

#include<iostream>
using namespace std;

int n;
int v[550][550];
int f[550][550];
int ans=-5000000;//因为数据范围是-10000到10000,并且n的取值范围是500,因此极限情况是输入的所有数字都是-10000,最大值也就是50*-10000,因此刚开始定义的ans要小于等于50* -10000.
int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= i; j++) {
			cin >> v[i][j];
		}
	}
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= i; j++) {
			if (j == 1) {
				f[i][j] = f[i - 1][j] + v[i][j];
			}
			else if (j == i) {
				f[i][j] = f[i - 1][j - 1] + v[i][j];
			}
			else
				f[i][j] = max(f[i - 1][j - 1]+v[i][j], f[i - 1][j]+v[i][j]);
		}
	}
	for (int i = 1; i <= n; i++) {
		 ans = max(ans, f[n][i]);
	}
	cout << ans;
	return 0;

}

 逆序思考问题:好处,每一个数字的左上角和右上角都有数字,不用考虑边界问题。

#include<iostream>
using namespace std;

int n;
int v[500][500];
int f[500][500];

int main() {
	cin >> n;
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= i; j++) {
			cin >> v[i][j];
		}
	}
	for (int i = n; i >=1; i--) {
		for (int j = 1; j <= i; j++) {
			
				f[i][j] = max(f[i+1 ][j]+v[i][j], f[i+1 ][j+1]+v[i][j]);
		}
	}
	cout << f[1][1] << endl;

	
	return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值