【刷题】动态规划——背包问题:能量石(Google Kickstart2019 Round B Problem B)【贪心,01背包,价值随体积增大而减小】

在这里插入图片描述
题目链接

考虑第i个石头和第i+1个石头,如果交换二者吃的顺序。

位置i位置i+1
交换前获得的能量EiEi+1 - Si * Li+1
交换后获得的能量Ei+1Ei - Si+1 * Li

将两位置相加
交换前:Ei + Ei+1 - Si * Li+1
交换后: Ei+1 + Ei - Si+1 * Li
交换后 - 交换前:Si * Li+1 - Si+1 * Li
若想交换后更大,则Si * Li+1 - Si+1 * Li > 0,也就是Si / Li > Si+1 / Li+1

换而言之,就是Si / Li大的放在后面,能让解更优
因此将Si / Li从小到大排序,得到的就是最优的顺序


接下去按照01背包的问题来做,区别是多了减少能量的条件,时间越长物品价值越低(普通的背包体积大小对物品价值并没有影响),因此f[i, j]的表示要改成 “时间恰好是j”。

f[i, j]表示从前i个能量石中选,时间恰好为j获得的能量最大值。
不吃第i个能量石:f[i, j] = f[i-1, j]
第i个能量石: f[i, j] = f[i-1, j-s] + e - (j - s) * l

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int t, n, m, f[10005];
struct node {
	int s, e, l;
}stone[105];

bool cmp (const node &x, const node &y) {
	return x.s * y.l < y.s * x.l;
}

int main() {
	scanf("%d", &t);
	for (int num = 1; num <= t; num ++) {
		scanf("%d", &n);
		m = 0;
		for (int i = 1; i <= n; i ++) {
			scanf("%d%d%d", &stone[i].s, &stone[i].e, &stone[i].l);
			m += stone[i].s;
		}
		sort(stone + 1, stone + n + 1, cmp);
		memset(f, 0xc0, sizeof(f));
		f[0] = 0;
		for (int i = 1; i <= n; i ++) {
			for (int j = m; j >= stone[i].s; j--) {
				f[j] = max(f[j], f[j - stone[i].s] + stone[i].e - (j - stone[i].s) * stone[i].l);
			}
		}
		int ans = 0;
		for (int i = 0; i <= m; i ++) {
			ans = max(ans, f[i]);
		}
		printf("Case #%d: %d\n", num, ans);
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值