01背包问题
题目链接:01背包问题
特点:物品只有一件
#include<iostream>
using namespace std;
int dp[1000005];
int main()
{
int n,m;
int price[1005],cost[1005];
cin>>n>>m;
for(int i=1;i<=n;++i)
{
cin>>cost[i]>>price[i];
}
for(int i=1;i<=n;++i)
{
for(int j=m;j>0;j--)
{
if(j>=cost[i]) dp[j]=max(dp[j],dp[j-cost[i]]+price[i]);
}
}
cout<<dp[m];
return 0;
}
完全背包问题
题目链接:完全背包问题
特点:物品有无限件
不同点:循环价格时从0~m
#include<iostream>
using namespace std;
int dp[1000005];
int main()
{
int n,m;
int price[1005],cost[1005];
cin>>n>>m;
for(int i=1;i<=n;++i)
{
cin>>cost[i]>>price[i];
}
for(int i=1;i<=n;++i)
{
for(int j=1;j<=m;++j)
{
if(j>=cost[i]) dp[j]=max(dp[j],dp[j-cost[i]]+price[i]);
}
}
cout<<dp[m];
return 0;
}
多重背包问题I
题目链接:多重背包问题I
特点:每个物品有有限个数件
解法一:三重循环 循环第i件物品取k件更新dp数组
#include<iostream>
using namespace std;
int dp[10005];
int main()
{
int n,m;
int cost[105],price[105],num[105];
cin>>n>>m;
for(int i=1;i<=n;++i)
{
cin>>cost[i]>>price[i]>>num[i];
}
for(int i=1;i<=n;++i)
{
for(int j=m;j>0;j--)
{
for(int k=1;k<=num[i]&&j>=k*cost[i];k++)
{
dp[j]=max(dp[j],dp[j-k*cost[i]]+k*price[i]);
}
}
}
cout<<dp[m];
}
多重背包问题II
思路:二进制优化
将有num个的物品等价拆分为几个物品,如:
将体积为2,价值为3,数量为12的物品,拆分为
序号 | 体积 | 价值 | 数量 |
---|---|---|---|
1 | 2 | 3 | 1 |
2 | 4 | 6 | 1 |
3 | 8 | 12 | 1 |
4 | 10 | 15 | 1 |
拆分为这四个物品,这四个物品的选取组合可以表示任意数量的原物品
例如:
若原物品放五个为最优解,即等价于放物品1和物品3
若原物品放10个为最优解,即等价于放物品1、物品3、物品4
AC代码
#include<iostream>
using namespace std;
const int MAXN = 20005;
int cost[MAXN],price[MAXN];
int dp[2000005];
int n,m;
int cos,pri,num;
int main()
{
cin>>n>>m;
int t=1;
for(int i=1;i<=n;++i)
{
cin>>cos>>pri>>num;
for(int k=1;k<=num;k*=2)
{
cost[++t]=k*cos;
price[t]=k*pri;
num-=k;
}
if(num>0)
{
cost[++t]=num*cos;
price[t]=num*pri;
}
}
for(int i=1;i<=t;++i)
{
for(int j=m;j>0;j--)
{
if(j>=cost[i]) dp[j]=max(dp[j],dp[j-cost[i]]+price[i]);
}
}
cout<<dp[m];
return 0;
}