解析
表示所有满足从前i个物品选k个物品,总体积超过j的所有选法中价值最大的选法
因为每件物品可以无限选,所以每件物品可以选择多少件的情况如下:
- 从前i个物品中选0个
- 从前i个物品中选1个
- 从i个物品中选2个
- 从i个物品中选k-1个
- 从i个物品中选k个
一.第i件物品选0个,也就说第i件物品不选,那么选的就是从前i-1个物品中选,且体积不能超过j的选法。用公式表示为 :
二.从第i个物品中选k个,求最大价值,同样划分为子问题:
1.因为所有选法,第i个物品都选了k个,我们可以不包含第k件物品
2.因为去了第k个,相当于不包括第i个物品,所以应该是从前i-1个物品中选,且体积不能超过 (要给第k个物品留空间)
3.再把k个物品i加回来,即
4.所以从第i个物品中选K个选法是
ps:
从前i个物品中选0个的选法包含在从前i个物品中选k个的选法中因为从前i个物品中选0个的选法实际上就是从前i个物品中选k个,其中k为0的选法
code
#include<iostream>
using namespace std;
const int N=1010;
int dp[N][N];
int w[N],v[N];
int main()
{
int n,m;
cin>>n>>m;
for(int i=0;i<n;++i)
{
cin>>v[i]>>w[i];
}
for(int i=1;i<=n;++i)
for(int j=0;j<=m;++j)
for(int k=0;k*v[i]<=j;++k)//前i个物品选k个,k个物品最大体积不能超过j,因为j是总体积,这里还要给第i个物品留空间
dp[i][j]=max(dp[i][j],dp[i-1][j-k*v[i]+k*w[i]]);
cout<<dp[n][m]<<endl;
return 0;
}
之所以超时是因为有三层for循环,而数据范围如下:
1000行,每行最大1000,一行三层循环就已经1e9了。
优化
f[i , j ] = max( f[i-1,j] , f[i-1,j-v]+w , f[i-1,j-2*v]+2*w , f[i-1,j-3*v]+3*w , .....)
f[i , j-v]= max( f[i-1,j-v] , f[i-1,j-2*v] + w , f[i-1,j-3*v]+2*w , .....)
由上两式,可以发现
f[i,j]的每一项都比 f[i,j-v]的每一项多一个w.
可得出如下递推关系:
f[i][j]=max(f[i,j-v]+w , f[i-1][j])
#include<iostream>
using namespace std;
const int N=1010;
int dp[N][N];
int w[N],v[N];
int main()
{
int n,m;
cin>>n>>m;
for(int i = 1 ; i <= n ;i ++)
{
cin>>v[i]>>w[i];
}
for(int i = 1 ; i <=n ;i++)
for(int j = 0 ; j <=m ;j++)
{
dp[i][j] = dp[i-1][j];
if(j-v[i]>=0)//前i个物品选k个的体积大于0
dp[i][j]=max(dp[i][j],dp[i][j-v[i]]+w[i]);
}
cout<<dp[n][m]<<endl;
return 0;
}