[隊內測試Day10.22T3][codevs1684]垃圾陷阱

題目←

考試的時候沉迷T4而忽略掉的DP題
也是該複習DP了……

摸魚:
設dp[i][j]爲第i個物品在時間爲j時的最大高度
轉移更直觀一些
dp[i][j] = dp[i - 1][j - l[i].t];//吃
dp[i][j] = dp[i - 1][j] + l[i].h//堆

注意在吃的時候,需要滿足j - l[i].t >= l[i].f,堆得話需滿足j >= l[i].f
意義爲在使用了i - 1堆垃圾而到達第i堆垃圾扔下的時間的情況,這樣纔是合法的

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 20000 + 50;
struct edge{
    int f,t,h;
}l[MAXN << 1];
int D,G,dp[105][MAXN],lim;
bool cmp(edge a,edge b){
    return a.f < b.f;
}
int main(){
    scanf("%d%d",&D,&G);
    for(int i = 1;i <= G;i ++){
        scanf("%d%d%d",&l[i].f,&l[i].t,&l[i].h);
    }
    sort(l + 1,l + G + 1,cmp);
    memset(dp,-1,sizeof(dp));
    for(int i = 0;i <= 10;i ++){
        dp[0][i] = 0;
    }
    lim = 10;
    for(int i = 1;i <= G;i ++){
        if(lim < l[i].f){
            printf("%d",lim);
            return 0;
        }
        lim += l[i].t;
        for(int j = 0;j <= lim;j ++){
            dp[i][j] = dp[i - 1][j];
            if(j >= l[i].f){
                if(j - l[i].t >= l[i].f)dp[i][j] = max(dp[i][j],dp[i - 1][j - l[i].t]);
                if(dp[i - 1][j] != -1)
                    dp[i][j] = max(dp[i][j],dp[i - 1][j] + l[i].h);
                if(dp[i][j] >= D){
                    printf("%d\n",l[i].f);
                    return 0;
                }
            }
        }
    }
    /*for(int i = 1;i <= G;i ++){
        for(int j = 0;j <= lim;j ++){
            printf("%d ",dp[i][j]);
        }
        printf("\n");
    }*/
    printf("%d",lim);
    return 0;
}

正解:
如果不看題解是沒有這種思路的……
充分體現了DP的另一個技巧:設計不出方程的時候把數組下標和它存的內容換一換
設f[j]爲到達高度i時的最大生命時間
對於垃圾i,有吃和堆的情況:

f[j + l[i].h] = max(f[j + l[i].h],f[j]);//堆,高度增時間不增
f[j] += l[i].w //吃,吃掉時一定爲這一高度的最優情況

關於垃圾到達時間的限制,僅當f[j] >= 垃圾i的到達時間時,纔可以選擇堆或吃
否則爲i之前的垃圾無法在i到來的時刻堆到高度j,該高度不合法。
如果無法到達則全部吃掉可存活最長時間,輸出f[0]
確實有點像帶限制的01揹包?

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int D,n;
struct edge{
    int f,h,w;
}l[23333];
int f[233333];
int solve(){
    f[0] = 10;
    for(int i = 1;i <= n;i ++){
        for(int j = D;j >= 0;j --){
            if(l[i].f <= f[j]){
                f[j + l[i].h] = max(f[j + l[i].h],f[j]);
                if(j + l[i].h >= D)return l[i].f;
                f[j] += l[i].w;
            }
        }
    }
    return -1;
}
bool cmp(edge a,edge b){
    return a.f < b.f;
}
int main(){
    scanf("%d%d",&D,&n);
    for(int i = 1;i <= n;i ++){
        scanf("%d%d%d",&l[i].f,&l[i].w,&l[i].h);
    }
    sort(l + 1,l + n + 1,cmp);
    int temp = solve();
    if(temp == -1)temp = f[0];
    printf("%d",temp);
    return 0;
}

發佈了103 篇原創文章 · 獲贊 11 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章