01背包和完全背包问题
- 01背包
问题描述:背包容量为T,有n件物品,每件物品只有一个,每件物品的重量为[w[1],w[2],w[3]…w[n]],每件物品对应的价值为[v[1],v[2],v[3]…v[n]],现在要求在背包容量之内,使装入背包物品的总价值最大。
低阶版本:
#include <iostream>
using namespace std;
int get_max(const int& x1,const int& x2)
{
return x1>x2? x1:x2;
}
int main()
{
int T,n;
cin>>T>>n;
int w[n+1];
int v[n+1];
for(int i=1;i<=n;++i)
{
cin>>w[i]>>v[i];
}
int dp[n+1][T+1];
for(int i=0;i<=T;++i)
dp[0][i]=0;
for(int i=0;i<=n;++i)
dp[i][0]=0;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=T;++j)
{
if(j<w[i])//如果拿不下此物品情况
dp[i][j]=dp[i-1][j];
else//拿的下,但是在不拿和拿之间选一个最大值
dp[i][j]=get_max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);
}
}
cout<<endl;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=T;++j)
cout<<dp[i][j]<<" ";
cout<<endl;
}
cout<<dp[n][T];
return 0;
}
输出dp表:
优化版本:
因为求dp[i][j]时,只用到了i-1的dp值,所以可以将数组压缩到一维,使用滚动数组
#include <iostream>
using namespace std;
int get_max(const int& x1,const int& x2)
{
return x1>x2? x1:x2;
}
int main()
{
int T,n;
cin>>T>>n;
int w[n+1];
int v[n+1];
for(int i=1;i<=n;++i)
{
cin>>w[i]>>v[i];
}
int dp[T+1];
for(int i=0;i<=T;++i)
{
dp[i]=0;
}
for(int i=1;i<=n;++i)
{
for(int j=T;j>=1;--j)
{
if(j<w[i])//如果拿不下此物品情况
dp[j]=dp[j];
else//拿的下,但是在不拿和拿之间选一个最大值
dp[j]=get_max(dp[j],dp[j-w[i]]+v[i]);
}
}
cout<<dp[T];
return 0;
}
- 完全背包
问题描述:背包容量为T,有n件物品,每件物品只有无限个,每件物品的重量为[w[1],w[2],w[3]…w[n]],每件物品对应的价值为[v[1],v[2],v[3]…v[n]],现在要求在背包容量之内,使装入背包物品的总价值最大。
低阶版本:
#include <iostream>
using namespace std;
int get_max(const int& x1,const int& x2)
{
return x1>x2? x1:x2;
}
int main()
{
int T,n;
cin>>T>>n;
int w[n+1];
int v[n+1];
for(int i=1;i<=n;++i)
{
cin>>w[i]>>v[i];
}
int dp[n+1][T+1];
for(int i=0;i<=T;++i)
dp[0][i]=0;
for(int i=0;i<=n;++i)
dp[i][0]=0;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=T;++j)
{
if(j<w[i])//如果拿不下此物品情况
dp[i][j]=dp[i-1][j];
else//拿的下,但是在不拿和拿之间选一个最大值
dp[i][j]=get_max(dp[i-1][j],dp[i][j-w[i]]+v[i]);
}
}
cout<<endl;
for(int i=1;i<=n;++i)
{
for(int j=1;j<=T;++j)
cout<<dp[i][j]<<" ";
cout<<endl;
}
cout<<dp[n][T];
return 0;
}
输出dp表:
优化版本:
#include <iostream>
using namespace std;
int get_max(const int& x1,const int& x2)
{
return x1>x2? x1:x2;
}
int main()
{
int T,n;
cin>>T>>n;
int w[n+1];
int v[n+1];
for(int i=1;i<=n;++i)
{
cin>>w[i]>>v[i];
}
int dp[T+1];
for(int i=0;i<=T;++i)
{
dp[i]=0;
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=T;++j)//顺序
{
if(j<w[i])//如果拿不下此物品情况
dp[j]=dp[j];
else//拿的下,但是在不拿和拿之间选一个最大值
dp[j]=get_max(dp[j],dp[j-w[i]]+v[i]);
}
}
cout<<dp[T];
return 0;
}
终极版本:
#include <iostream>
using namespace std;
int get_max(const int& x1,const int& x2)
{
return x1>x2? x1:x2;
}
int main()
{
int T,n;
cin>>T>>n;
int w[n+1];
int v[n+1];
for(int i=1;i<=n;++i)
{
cin>>w[i]>>v[i];
}
int dp[T+1];
for(int i=0;i<=T;++i)
{
dp[i]=0;
}
for(int i=1;i<=n;++i)
{
for(int j=w[i];j<=T;++j)//顺序,并且可以从w[i]处开始判断
{
dp[j]=get_max(dp[j],dp[j-w[i]]+v[i]);
}
}
cout<<dp[T];
return 0;
}