浅谈(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_ileqslant 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
",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
",f[T]);
return 0;
}