codeforce 864E

codeforce-864E

题 意:小明家着火了,有n的物品需要救援,给出,每个物品的抢救时间t,彻底被烧毁的时间d,和价值p。如果小明先抢救物品a,再抢救物品b,那么只有当ta+tb

3
3 7 4
2 6 5
3 7 6

输出样例:

11
2
2 3 

思 路:选或不选的最优决策,显然是一道0,1背包。关键点是什么呢?
关键点1:按时间排序,显然时间最少的应该放在前面,决则这样可以使背包跑出来的结果最优,因为我可以先拿时间少的,然后再去拿时间大的,而可能不能先拿时间大,再拿时间少的。不排序,跑出来的结果,不是最优的。
关键点2:状态转移方程dp[i][j] 到第i个时间点j时所救援的最大物品价值.
dp[i][j] = max(dp[i-1][j],d[i-1][j-ti]+pi)
初始状态dp[0][j] = 0
关键点3:路径输出 用一个last[i][j] 数组 记录 到第i个时间点j时 是否选择了i 然后再从dp[n][j]最大价值中,回溯就好。

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 100+5;
struct node{
    int t,d,p,id;
}a[maxn];
int dp[maxn][2001]; //前i个到时间j所能获取的最大价值
/*
    状态转移方程 dp[i][j] = max(dp[i-1][j],dp[i-1][j-ti]+pi);
*/
bool cmp(node a, node b){
    return a.d < b.d;
}   //这样可以保证再前面选的经可最大
int last[maxn][2000+1];
int n;

int main(){
    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+n+1,cmp);
    memset(dp,0,sizeof(dp));
    for(int i=1;i<=n;i++){
        for(int j=1;j<=2000;j++){
            dp[i][j] = dp[i-1][j];
            if(j >= a[i].t && j<a[i].d){
                if(dp[i-1][j-a[i].t]+a[i].p > dp[i][j]){
                    dp[i][j] = dp[i-1][j-a[i].t]+a[i].p;
                    last[i][j] = i;
                }
            }
        }
    }

    vector<int> vec;
    int ans = 0,index;
    for(int i=1;i<=2000;i++){
        if(dp[n][i] > ans){
            ans = dp[n][i];
            index = i;
        }
    }
    vec.clear();
    int level = n,pos = index;
    while(level >= 1 && pos >=0){
        if(last[level][pos] > 0){
            vec.push_back(a[last[level][pos]].id);
            pos-=a[last[level][pos]].t;
        }
        level--;
    }
    reverse(vec.begin(),vec.end());
    printf("%d\n",ans);
    printf("%d\n",vec.size());
    for(int i=0;i<vec.size();i++){
        printf("%d%c",vec[i],i==n-1?'\n':' ');
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37129433/article/details/81110411