第一种思路:将能放进背包的第i种物品看做一件物品,转化为0-1背包问题:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int NN=1000;
const int TT=1000;
int v[NN+1];
int t[NN+1];
int c[NN+1][TT+1];
int main()
{
int T,N,i,j;
cin>>T>>N;
for(i=1; i<=N; i++)
cin>>t[i]>>v[i];
i=0;
memset(c,0,sizeof(c));
for(i=1; i<=N; i++)
for(int j=1; j<=T; j++)
for(int j=1; j<=T; j++)
{
if(t[i]<=j)
{
int k=j/t[i];
c[i][j]=max(c[i-1][j-k*t[i]]+k*v[i],c[i-1][j]);
}
else
c[i][j]=c[i-1][j];
}
cout<<c[N][T]<<endl;
return 0;
}
优化的方案是从状态本身入手:在0-1背包问题中,状态转移方程是dp[i][j]=max(dp[i-1][j],dp[i-1][j-m[i]]+w[i])
其中dp[i-1][j-m[i]]+w[i] 的含义是考虑放入第i种物品1件,dp[i][j]含义是将前i件物品放进容量为j的背包时的背包价值的最大值
那么dp[i-1][j-m[i]]的含义为:将前i-1件物品放进容量为j-m[i](此时因为放进了一件物品i,所以背包剩余容量是j-m[i])
下面为了解决完全背包问题,我们换一种思考的方式:
将dp[i][j]的含义改变成:放入前i种物品若干件进入容量为j的背包时背包的最大价值,我们再去考虑状态转移方程:
dp[i][j]=max(dp[i-1][j],dp[i][j-m[i]]+w[i])其中括号里前一项表示不放第i种物品,这是好理解的,后一项表示的含义是至少放进1件第i种物品,直接含义是放入前i种物品若干件进入容量为j-m[i]的背包时背包的最大价值(可能放进第i种物品前已经放进了若干件第i种物品)
但是至少会放进一件第i种物品
下面是利用滚动数组优化的代码:
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=1005;
int M,n;
int w[maxn];
int m[maxn];
int dp[maxn];
int main()
{
memset(dp,0,sizeof(dp));
cin>>M>>n;
for(int i=1; i<=n; ++i)
cin>>m[i]>>w[i];
for(int i=1; i<=n; ++i)
for(int j=m[i]; j<=M; ++j)
{
dp[j]=max(dp[j],dp[j-m[i]]+w[i]);
}
cout<<dp[M]<<endl;
return 0;
}