Fire

0 篇文章 0 订阅

fire

原题:
CF864E Fire

题目

题解
思路

首先, 我们来证明一个东西:我们救东西的顺序为按销毁时间从早到晚, 那一定有一种情况是最优解。
证明:
若存在一个最优解不满足该证明, 则若我们重新将这几个东西按照销毁顺序重新排列, 那么我们只需要证明这个重新排列的顺序是可以成立的就行了。
那么我们来看一下, 设原来的前 i i i项和记为 S i Si Si, 第 i i i项为 A i Ai Ai, 新的分别为 S ′ i S'i Si A ′ i A'i Ai。明显可得 S n = S ′ n , A n ≤ A ′ n Sn = S'n, An \le A'n Sn=Sn,AnAn, 那么第n项肯定成立, 而原序列去掉新序列中的第n项一定成立(这很显然嘛),那么若长度为 n − 1 n - 1 n1的序列变化成立, 那长度为 n n n的序列也成立。 而最后只有一项时是明显成立,所以证毕。
接下来我们回到原来的题目。首先我们定义状态为 d p [ i ] [ j ] dp[i][j] dp[i][j], 表示前 i i i个元素在第 j j j时刻前救出的最大价值, 而第 i i i个元素的销毁时间我们知道, 所以我们就只能将这个元素放在销毁时间之前救出, 然后就如同 0 / 1 0/1 0/1背包一样救援时间当成体积, 价值当成价值。最后有一点要注意, 因为有销毁时间的存在, 所以我们的答案是在数组里最大的那个。

代码:

#include <cstdio>
#include <algorithm>
using namespace std;

#define MAXN 2000

int st[MAXN + 5], sd[MAXN + 5], sp[MAXN + 5];
pair <int, int> s[MAXN + 5];
int dp[MAXN + 5];
int answer [MAXN + 5];
bool f[MAXN + 5][MAXN + 5];
int sa[MAXN + 5];

int main () {
	int n;
	int sum = 0;
	
	scanf ("%d", &n);
	for (int i = 1; i <= n; i ++) {
		scanf ("%d %d %d", &st[i], &sd[i], &sp[i]);
		s[i].first = sd[i];
		s[i].second = i;
		sum = max (sum, sd[i]);
	}
	sort (s + 1, s + 1 + n);
	for (int i = 1; i <= n; i ++) {
		for (int j = s[i].first - 1; j >= st[s[i].second]; j --) {
			if (dp[j] < dp[j - st[s[i].second]] + sp[s[i].second]) {
				dp[j] = dp[j - st[s[i].second]] + sp[s[i].second];
				f[i][j] = 1;
				answer[j] = answer[j - st[s[i].second]] + 1;
			}
		}
	}
	
	int smax = 0, maxl = 0;
	
	for (int i = 1; i <= sum; i ++) {
		if (dp[i] > smax) {
			smax = dp[i];
			maxl = i;
		}
	}
	printf ("%d\n%d\n", smax, answer[maxl]);
	
	int tot = 0;
	
	for (int i = n, j = maxl; i > 0; i --) {
		if (f[i][j]) {
			sa[++tot] = i;
			j -= st[s[i].second]; 
		}
	}
	for (int i = tot; i >= 1; i --) {
		printf ("%d ", s[sa[i]].second);
	}
} 
  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值