背包入门–01背包
相信DD的背包九讲已经讲的很详细了,不过我带来了更适合入门者学习的模板,开始吧。
01背包的题目描述的标志
描述: n件物品,容量为v,第i件物品的重量为w[i],价值为v[i],求怎么装可以使背包装的价值之和最大
理解:每件物品只能拿一次,每件物品可以选择拿或不拿,所以我们从前i件物品开始考虑拿或者不拿;
拿第i件物品:背包总价值就是第i件价值加上前i-1价值的总和;用表达式表示的话就是总价值=v[i]+前i-1的价值总和
这里我们设f[i][j]表示前i件物品放在容量为j的最大价值
不拿第i件物品:背包的总价值就很简单计算了,就直接是前i-1件物品的总价值了
上表达式
f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i])
相信这个不用详细解释了,上面解释的蛮清楚的
代码怎么实现?上代码!
代码二维数组一般不用哈哈哈哈,时间和空间复杂度较大,不过有挺多优化的方法,就是把二维数组变成一维数组,那时间复杂度就变成了0(n)了
如何优化?
先把f[i][j]改为一维数组f[j],那么f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i])这个关键AC代码将如何变呐?
请看下面讲述。
AC关键模板代码
上面的描述万一你看不懂其实对你做01背包问题不是特别大;不过最好还是得理解,实在不行就记住模板吧;以后写多就慢慢的理解了
for (int i = 1; i <= n; i++)
for (int j = V; j >= 0; j--)
f[j] = max(f[j], f[j - w[i]] + v[i]);
这个就是01背包的关键代码,超级有用!!!
继续改进在循环部分可以继续改
因为每次拿与不拿有一个关键因素就是当前拿的物品是否超过当前背包剩余的容量,所以在循环部分可以继续改进
for (int i = 1; i <= n; i++)
for (int j = V; j >= w[i]; j--)
f[j] = max(f[j], f[j - w[i]] + v[i]);
上面就是我们A题的关键代码,好了学习上面的这些就可以去A 01背包问题了
其实这个代码还可以继续优化,不过在这里对于新手就足够了,想继续深入了解,上度娘或者看DD的背包九讲哈哈哈哈
好了可以开始A题
洛谷2925
题目描述
农民john面临一个很可怕的事实,因为防范失措他存储的所有稻草给澳大利亚蟑螂吃光了,他将面临没有稻草喂养奶牛的局面。在奶牛断粮之前,john拉着他的马车到农民Don的农场中买一些稻草给奶牛过冬。已知john的马车可以装的下C(1 <= C <=50,000)立方的稻草。
农民Don有H(1 <= H <= 5,000)捆体积不同的稻草可供购买,每一捆稻草有它自己的体积(1 <= V_i <= C)。面对这些稻草john认真的计算如何充分利用马车的空间购买尽量多的稻草给他的奶牛过冬。
现在给定马车的最大容积C和每一捆稻草的体积Vi,john如何在不超过马车最大容积的情况下买到最大体积的稻草?他不可以把一捆稻草分开来买。
输入输出格式
输入格式:
第一行两个整数,分别为C和H
第2…H+1行:每一行一个整数代表第i捆稻草的体积Vi
输出格式:
一个整数,为john能买到的稻草的体积
输入输出样例
输入样例#1:
7 3
2
6
5
输出样例#1:
7
AC代码
#include<bits/stdc++.h>
using namespace std;
int f[111111];
int main()
{
int n,m,i,j,a[111111];
cin>>m>>n;
for (i=1;i<=n;i++) scanf("%d",&a[i]);
for (i=1;i<=n;i++)
{
for (j=m;j>=a[i];j--)
f[j]=max(f[j],f[j-a[i]]+a[i]);
if (f[m]==m) {printf("%d",m); return 0;}//优化,如果已经达到最好的结果(装满),就直接退掉
}
printf("%d",f[m]);
}
这也就是我这周学习的到的其中的一个简单的算法,之后完全背包问题等,DP入门还没学会哎