1129. 【动态规划】游园礼物(数字三角形2)(保姆教程)

题目描述

新年到了,学校里组织了有趣的游园活动!
每个活动场地都被设计成一个三角形,在三角形的每个点位都设有一台机器人给同学们派发礼物。每个机器人派发的礼物数量是各不相同的,但同一个机器人每次派发礼物的数量是不变的。
小王有其中一张活动场地地图(如下图)。

7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

活动要求小王从三角形顶部出发,向下行走获取礼物,但只能选择向左下走或向右下走,一直走到最底层,并且有一个点位,是可以获得两次礼物的。上图中,要获得最大礼物数,小王可以在(3,1) 处拿两次礼物。
请你帮小王计算下,他最多能获得的礼物数是多少呢

输入

从文件 num.in 中读入数据。

第一行一个整数 n,表示地图有 n 行;
第 2~n+1 行,为每个点位机器人派发一次礼物的数量,数字之间空格隔开。

输出

输出到文件 num.out 中。

一个整数,表示小王获得礼物数量总和的最大值。

样例数据

输入 #1

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

输出 #1

38

数据范围限制

对于 30% 的数据,1≤n≤250;
对于所有数据,1≤n≤1000。
由于活动经费有限,一个机器人派发一次礼物的数量保证在 10000 以内。

思路

这个题目需要使用动态规划的方法去做:
首先根据动态规划的三步法:

1 - 初始化dp数组
dp[x][y][f] 表示x,y位置的最优解, f表示是否拿过两次礼物

for (int i = 1; i <= n; i++) 初始化第一行
{
	dp[1][i][0] = Map[1][i]; 第一行只有可能是他自己本身
	dp[1][i][1] = Map[1][i] * 2; 如果拿过2次一定是将自己本身的元素拿了2}

2 - 确定状态转移方程
dp[x][y][0] = max(dp[x - 1][y], dp[x - 1][y - 1]) + Map[x][y] 如果当前位置没有相加过, 直接递推计算
dp[x][y][1] = max(选择当前元素算两次, 只算加一次(把机会留给后边的数字))

int tmp1 = max(dp[x - 1][y][0], dp[x - 1][y - 1][0]) + Map[x][y] * 2;
int tmp2 = max(dp[x - 1][y][1], dp[x - 1][y][1]) + Map[x][y];

dp[x][y][1] = max(tmp1, tmp2);
3 - 结果的计算
遍历最后一行 计算数组的最大值

int ans = 0;
for (int i = 1; i <= n; i++) ans = max(ans, max(dp[n][i][1], dp[n][i][0]));
printf("%d", ans);

C++AC代码

#include <stdio.h>
#include <string.h>

#define max(a,b) ((a) > (b) ? (a) : (b))
int dp[1005][1005][2], Map[1005][1005], n;
int main()
{
	// freopen("num.in", "r", stdin), freopen("num.out", "w", stdout);
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= i; j++) scanf("%d", &Map[i][j]);

	for (int i = 1; i <= n; i++) // 初始化第一行
	{
		dp[1][i][0] = Map[1][i];
		dp[1][i][1] = Map[1][i] * 2;
	}

	for (int i = 1; i <= n; i++)
	{
		for (int j = 1; j <= i; j++)
		{
			dp[i][j][0] = max(dp[i - 1][j][0], dp[i - 1][j - 1][0]) + Map[i][j];
			int tmp1, tmp2;
			tmp1 = max(dp[i - 1][j][0], dp[i - 1][j - 1][0]) + Map[i][j] * 2;
			tmp2 = max(dp[i - 1][j][1], dp[i - 1][j - 1][1]) + Map[i][j];
			dp[i][j][1] = max(tmp1, tmp2);
		}
	}
	int ans = 0;
	for (int i = 1; i <= n; i++) ans = max(ans, max(dp[n][i][1], dp[n][i][0]));
	printf("%d", ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值