Codeforces Round #436 (Div. 2) 864E. Fire

那天晚上发现有场cf时间比较早就跑去打了一下,只写出ABCDE的我(一次都没被hack,也一次都没去hack)……


地址:Codeforces Round #436 (Div. 2) 864E. Fire


题目:

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 ti seconds 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 ≤ 20, 1 ≤ di ≤ 2 000, 1 ≤ 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 2 seconds. 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 3 seconds, but this item will already be completely burned by this time.


题解:

至于题意什么的怕误导人…………google翻译
算了还是讲一下吧:
就是一个人家里着火了,要抢救一些重要的东西,每件东西都有价值,抢救每一件东西也要花费一些时间,每件东西燃尽也需要时间(如果救出来的时候这个物品刚好燃尽的话,就不算就出来,参考样例),而这些数值往往不相同(可能相同)。
问该人能抢救的最大价值,和抢救方案.
输入:
第一行一个数 n 表示有 n 件物品待抢救。
之后 n 行,每行 3 个整数 ti,di,pi(1ti20,1di2000,1pi20) 分别表示救出第 i 个物品所花的时间,这个物品燃尽的时间和这个物品的价值.
输出:
第一行是一个整数表示最大价值。
第二行是一个整数表示救出物品数目。
第三行按照救出顺序输出救出物品的编号。


这道题的算法就是背包了,之前练了下背包所以比较敏感。
f[i][j] 表示现在第 i 个物品,时间已经到 j 秒时的最大价值。对于每个物品有两种操作,就是拿与不拿,开个 bool 类来保存一下当前状态是不是取了第 i 个物品。而且在每次 max 更新的时候记录下是从上次那个状态更新过来,这样我们就可以直接从最后的物品来回溯到第一个物品,并且通过 bool 数组来获取了哪些物品。
当然所有的物品读入后还需要按 d 值从小到大排序,因为每个物品的状态都要从之前更早的时间更新而来,如果一个很早就燃尽的物品放到后面来更新的话,就没法更新它燃尽之后的状态了。


代码:

#include
#include
#include
#include
using namespace std;
#define ll long long
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int f[105][2005];
int last[105][2005];
bool vis[105][2005];
int n,ans,mxt,num;
int sta[105],top;
struct node{
    int a,b,c,num;
}x[105];

bool cmp(node a,node b){
    return a.b < b.b;
}

int main(){
    n = read();
    for(int i = 1;i <= n;i++){
        x[i].a = read(); x[i].b = read(); x[i].c = read();
        x[i].num = i;
        mxt = max(mxt,x[i].b);
    }
    sort(x+1,x+n+1,cmp);
    for(int i = 1;i <= n;i++){
        for(int j = x[i].a;j < x[i].b;j++){
            if(f[i][j] <= f[i-1][j-x[i].a]+x[i].c){
                f[i][j] = f[i-1][j-x[i].a]+x[i].c;
                last[i][j] = j-x[i].a;
                vis[i][j] = true;
            }
        }
        for(int j = 0;j < mxt;j++){
            if(f[i][j] <= f[i-1][j]){
                f[i][j] = f[i-1][j];
                last[i][j] = j;
                vis[i][j] = false;
            }
        }
    }
    for(int i = 0;i < mxt;i++){
        if(ans < f[n][i]){
            ans = f[n][i];
            num = i;
        }
    }
    printf("%d\n",ans);
    for(int i = n;i >= 1;i--){
        if(vis[i][num]){
            sta[++top] = x[i].num;
        }
        num = last[i][num];
    }
    printf("%d\n",top);
    while(top > 0){
        printf("%d ",sta[top]);
        top--;
    }
    printf("\n");
    return 0;
}

你可能感兴趣的:(动态规划,codeforces,背包问题,题解)