洛谷【P1048】采药

浅谈\(DP\)https://www.cnblogs.com/AKMer/p/10437525.html

题目传送门:https://www.luogu.org/problemnew/show/P1048

像这种给你\(n\)个物品,每个物品有占用体积和价值,求\(m\)体积的背包能装下的最大的价值的问题就是\(01\)背包问题。

我们可以设\(f[i][j]\)表示从前\(i\)个物品中选取一些占用\(j\)的体积可以装的最大的价值。

那么转移如下:

\(f[i][j]=f[i-1][j](j<weight_i)\)

\(f[i][j]=max(f[i][j],max(f[i-1][j],f[i-1][j-weight_i]+value_i))(weight_i\leqslant j \leqslant m)\)

时间复杂度:\(O(nm)\)

空间复杂度:\(O(nm)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxT=1005,maxm=105;

int T,m;
int f[maxm][maxT];

int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

int main() {
    T=read(),m=read();
    for(int i=1;i<=m;i++) {
        int tim=read(),val=read();
        for(int j=0;j<tim;j++)f[i][j]=f[i-1][j];
        for(int j=tim;j<=T;j++)
            f[i][j]=max(f[i][j],max(f[i-1][j],f[i-1][j-tim]+val));
    }
    
    printf("%d\n",f[m][T]);
    return 0;
}

但是实际上我们可以把第一维省掉,然后倒着枚举体积。因为体积大的状态总是由体积小的状态更新得来,所以我倒着枚举体积实际上还是用的\(i-1\)个物品的状态来更新我当前加入第\(i\)个物品之后的状态。

时间复杂度:\(O(nm)\)

空间复杂度:\(O(m)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxT=1005,maxm=105;

int T,m;
int f[maxT];

int read() {
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    return x*f;
}

int main() {
    T=read(),m=read();
    for(int i=1;i<=m;i++) {
        int tim=read(),val=read();
        for(int j=T;j>=tim;j--)
            f[j]=max(f[j],f[j-tim]+val);
    }
    printf("%d\n",f[T]);
    return 0;
}
posted @ 2019-02-26 15:28  AKMer  阅读(217)  评论(0编辑  收藏  举报