[队内测试Day10.22T3][codevs1684]垃圾陷阱

来源:互联网 发布:月薪8000能招到java 编辑:程序博客网 时间:2024/06/06 06:45

题目←

考试的时候沉迷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;}

原创粉丝点击