Codeforces Round #436 (Div. 2) E. Fire (有放入顺序有关的01背包)

E. Fire
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Polycarp is in really serious trouble — his house is on fire! It's time to save the most valuable items. Polycarp estimated that it would take tiseconds to save i-th item. In addition, for each item, he estimated the value of di — the moment after which the item i will be completely burned and will no longer be valuable for him at all. In particular, if ti ≥ di, then i-th item cannot be saved.

Given the values pi for each of the items, find a set of items that Polycarp can save such that the total value of this items is maximum possible. Polycarp saves the items one after another. For example, if he takes item a first, and then item b, then the item a will be saved in ta seconds, and the item b — in ta + tb seconds after fire started.

Input

The first line contains a single integer n (1 ≤ n ≤ 100) — the number of items in Polycarp's house.

Each of the following n lines contains three integers ti, di, pi (1 ≤ ti ≤ 201 ≤ di ≤ 2 0001 ≤ pi ≤ 20) — the time needed to save the item i, the time after which the item i will burn completely and the value of item i.

Output

In the first line print the maximum possible total value of the set of saved items. In the second line print one integer m — the number of items in the desired set. In the third line print m distinct integers — numbers of the saved items in the order Polycarp saves them. Items are 1-indexed in the same order in which they appear in the input. If there are several answers, print any of them.

Examples
input
3
3 7 4
2 6 5
3 7 6
output
11
2
2 3 
input
2
5 6 1
3 3 5
output
1
1
1 
Note

In the first example Polycarp will have time to save any two items, but in order to maximize the total value of the saved items, he must save the second and the third item. For example, he can firstly save the third item in 3 seconds, and then save the second item in another 2seconds. Thus, the total value of the saved items will be 6 + 5 = 11.

In the second example Polycarp can save only the first item, since even if he immediately starts saving the second item, he can save it in 3seconds, but this item will already be completely burned by this time.

#include <stdio.h>
#include <string.h>
#include <bits/stdc++.h>
using namespace std;
struct node{
	int t, d, p, id;
	bool operator < (const node& x){
		return d < x.d;
	}
}a[101];
int dp[101][2001], pre[101][2001];
int main(){
	int n;
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i){
		scanf("%d %d %d", &a[i].t, &a[i].d, &a[i].p);
		a[i].id = i;
	}
	sort(a + 1, a + 1 + n);
	memset(dp, 0, sizeof(dp));
	for(int i = 1; i <= n; ++i){
		for(int j = 0; j <= n * 20; ++j){
			dp[i][j] = dp[i - 1][j];
			pre[i][j] = j;
			if(j >= a[i].t && j < a[i].d){
				if(dp[i][j] < dp[i - 1][j - a[i].t] + a[i].p){
					dp[i][j] = dp[i - 1][j - a[i].t] + a[i].p;
					pre[i][j] = j - a[i].t;
				}
			}
		}
	}
	int tot = 0;
	for(int i = 0; i <= n * 20; ++i){
		if(dp[n][i] > dp[n][tot]){
			tot = i;
		}
	}
	printf("%d\n", dp[n][tot]);
	vector<int> ans;
	for(int i = n; i >= 1; --i){
		if(pre[i][tot] != tot){
			ans.push_back(a[i].id);
			tot = pre[i][tot];
		}
	}
	printf("%d\n", ans.size());
	for(int i = ans.size() - 1; i >= 0; --i){
		printf("%d ", ans[i]);
	}
}

/*
题意:有个房子着火了,里面有100个物品,现在要把这些东西拿出来,每个物品有一个价值,拿出来所需的时间,和能承受火的最长时间,
问最多可以拿出多少价值的物品。

思路:
这题其实就是01背包,但是和放入背包的顺序很明显是有关的,一般这种问题都可以先思考这样一个问题,假如对于某一种解,解中所有物品我都
可以拿出来,需要按照什么顺序放入背包才可以保证解成立。对于这一题来说,假如相邻两个放入背包的是i,j,那么对于前面物品的放入顺序和
后面的放入顺序,对于这两个物品是没有影响的,因为当前后解成立时,影响因素只有t的求和,很显然前面的t求和是固定,加上i,j后求和也是
固定的(即前面的放入顺序对后面无影响),所以无论前后按什么顺序来放,只要解正确,那么就对i,j没有影响,现在我们单独考虑i,j。
根据题目的要求显然ti + tj < max(di, dj),就是如果两个全部拿出来总共用的时间不能超过其中某个最大承受火时间的物品的d,这个在假设中
保证的。如果先拿i,即ti + tj < di,如果先拿j,即tj + ti < dj,根据要求,如果两个都能拿,我们应该把d大的放在后面。
虽然这个顺序在某种情况下可能是不影响解的成立的,但是只有按顺序拿时才可以保证无法构造出一个反例去让解无法成立。
*/



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值