首发csdn,链接:https://blog.csdn.net/Colicsin/article/details/115404392?spm=1001.2014.3001.5501
问题描述:
现在给你一个容量为V的背包,有N个物品,其中第i件物品的重量为wi,价值为vi,每件物品可以拿无数次,问在有限的容量内,最多可以拿到多少价值的物品。
题目分析:
完全背包问题和01背包好相似诶,不过貌似又不是那么一样,对于完全背包问题的每一个物品不是两种状态了,而是k+1种状态:不拿或者拿1件或者拿2件或者....
刚开始看到完全背包的问题描述的时候,笔者脑海中还是蛮开心的,这不就是贪心吗?那我直接求性价比,用现在的包裹全部装性价比最高的,然后用剩下的装性价比第二高的...以此类推不就行了嘛。然而理想是美好的,但现实往往就是那么残酷QAQ
稍微举了个小案例,就发现貌似并不可以(当然不可以,不然还要dp干啥...想想还是挺有道理的orz)就拿一个例子来说:两个物品分别是5 5和8 7(分别表示重量和价值),背包是10要是按照贪心策略,那肯定是7了,但是答案却是5+5=10。
好吧,贪心确实不好用。(蒟蒻的怒吼~)
还记得之前讲过的01背包问题吗?当时在用滚动数组的思想去优化的时候,是不是出现了正序和倒序的问题?当时模拟了一遍中间过程,发现不能正序,因为正序会导致某一个物品被反复选择...诶!这不正好是我们现在想要的吗?(雀食蟀啊)
所以说其实就只要吧01背包的倒序改为正序就变成了完全背包问题了,至于原因,还是见01背包问题关于倒序的手动模拟部分
果然是车到山前必有路、世界是普遍联系的、联系具有客观性、条件性、多样性....(此人已疯不用搭理qwq)
所以我们只需要把倒序改为正序,就可以咯,代码如下...
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN=1e3+7;
int w[MAXN],N,V,v[MAXN],dp[100001];
int main()
{
memset(dp,0,sizeof(dp));
cin>>V>>N;
for(int i=1;i<=N;i++)
{
cin>>w[i]>>v[i];
}
for(int i=1;i<=N;i++)
{
for(int j=0;j<=V;j++)
{
if(j>=w[i])
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
cout<<dp[V]<<endl;
return 0;
}
完全背包问题,结束~