[TJOI2008] 小偷

TJOI2008小偷

题目背景

一位著名的小偷进入了一个充满宝石的储藏室,这个储藏室是由一连串房间构成的,房间的标号从0开始,想进入第i个房间就必须从第i-1个房间进入,如图:

题目描述

上图为三个房间的情况,黑色的部分为连通两个房间的门,从左向右的编号分别为0,1,2…。已知当小偷从第0个门进入储藏室时,储藏室的计时系统开始计时,每个门都有自己的关闭时间。每个屋里有不同种类的宝石,对于每种宝石,它的价值和小偷拿走它所耗费的时间也是不同的,为了简化问题,我们设想小偷在各个屋子之间走动的时间可以忽略不计,而且所有屋子里各种宝石的数量都是无限多的,那么请问小偷在能成功逃出来的情况下,可能获得宝石的最大价值。

附: 对于每扇门,小偷都必须在严格早于此门关闭的时候出来才可以。

输入格式

每组测试数据的第一行有两个整数N和M,分别代表储藏室有N个房间,并且有M种宝石。第二行中会有N个正整数,分别表示第i个门关闭的时间(门的编号从0开始),接下来的M行,每行有三个整数r,v和t,分别代表这种宝石所在的房间编号为r,它的价值为v,小偷拿走它所耗费的时间为t。

输出格式

输出小偷在成功逃出储藏室的情况下获得宝石的最大价值。

输入 #1

3 4
9 5 5
0 1 2
1 2 2
2 3 2
2 5 3

输出 #1

8

样例说明

我们知道,小偷应该在2时刻拿个3的,再在4时刻拿3的最后逃出到房间一,最后在一房间拿两个1的宝石,在八秒时逃出。

我们在求解时用到了两个变量一个是时间,一个是在的屋子。所以我们考虑,以这两个为变量,造一个函数。

分析算法

我们在每个房间里会有一些宝石,小偷的时间是一定的,宝石可以无限拿,他却让我们输出一个最大值,我们想到了dp。

我们不要被小偷从一号门进去而迷惑,小偷的神行无影,我们理解为小偷出生在最里面的第n间屋子里,在从外面跑,有点类似于纪念品那个题,当然在分析上会难很多。

我们的每一个门,会有自己关门的时间,对吧这就是体积v,每一个宝石就是商品,不要忘了要对关门的时间进行处理

于是乎,套上我的完全背包的模板,就有了1版的代码

定义

\(dp(i,j)\)表示在第从n到i个房间里,在j的时间内所能拿到的最贵价值

所求

\(dp(1,close[1]-1)\)即为所求我们将第\(1 到 i\)个门中关闭的的最小时间

dp转移方程

\[ dp(i,j)= \begin{cases} f(i+1,j)\\ f(i,j-1)\\ f(i,j-sto[i].tim[k])+sto[i].pri[k]; \end{cases} \]

#include 
#include 
#include 
using namespace std;
const int Maxdoor=55,Maxthi=110,Maxtime=1100;
struct Node{
    int pri[Maxthi],tim[Maxthi],num;
}sto[Maxdoor];
int n,m,x,min1,close[Maxdoor],dp[Maxthi][Maxtime];
int read(){
    int x=0;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        ch=getchar();
    }
    while(ch<='9'&&ch>='0'){
        x=(x<<1)+(x<<3)+(ch-'0');
        ch=getchar();
    }
    return x;
}
void read_in(){
    n=read();m=read();min1=0x3f3f3f3f;
    for(int i=1;i<=n;i++){
        close[i]=read();
        min1=min(min1,close[i]);
        close[i]=min(min1,close[i]);
    }
    for(int i=1;i<=m;i++){
        x=read();
        x++;
        sto[x].num++;
        sto[x].pri[sto[x].num]=read();
        sto[x].tim[sto[x].num]=read();
    }
    return;
}
void f(){
    for(int i=n;i>=1;i--){
        for(int j=1;j=0) dp[i][j]=max(dp[i][j],dp[i][j-sto[i].tim[k]]+sto[i].pri[k]);
            }
        }
    }
    printf("%d",dp[1][close[1]-1]);
}
int main() {
    freopen("1.in","r",stdin);
    read_in();
    f();
    return 0;
}

再经过考虑,我们可以直接降维,因为我们在求\(dp(i,j)\)的时候,只用到了\(dp(i+1)\)和之前的\(dp(i)\),所以我们可以降维

void f(){
    for(int i=n;i>=1;i--){
        for(int j=1;j=0) dp[j]=max(dp[j],dp[j-sto[i].tim[k]]+sto[i].pri[k]);
            }
        }
    }
    printf("%d",dp[close[1]-1]);
}

其实最开始我们想到代码的第4行为什么要传递最优值给下一个的,但是,连续提交的50pts,让我改了下样例就发现问题了,还是菜呀,因为决策里可以这一秒什么也不干呀,而且,主要原因还是背包体积的变化

你可能感兴趣的:([TJOI2008] 小偷)