01背包
背包有背包9讲,现在比较熟悉的就是01背包了,01背包的问题就是选或不选,那么用的就是动态规划(暂时还没有体验到这个特点。)
01 背包本质: dp[i][j] : 表示 第i行的最大的价值,现在的容量能装最大的价值。
变成一维的时候,从大的往小的放,缩小一维空间
现在就来讲一讲:
01背包:
题目
有N件物品和一个容量为V的背包。第i件物品的费用是c[i],价值是w[i]。求解将哪些物品装入背包可使价值总和最大。
基本思路
这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。
用子问题定义状态:即f[i][v]表示前i件物品恰放入一个容量为v的背包可以获得的最大价值。则其状态转移方程便是:
f[i][v]=max{f[i-1][v],f[i-1][v-c[i]]+w[i]}
这个式子很重要,基本的思路就是这样。
1.二维:二维很方便,基本上就是一个二维VN数组,
长度 | V |
---|---|
宽 | N |
Phone | $12 |
Pipe | $1 |
代码如下:这里给出第一行开始填,也可以最后一行开始填
#include "stdafx.h"
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
struct package
{
int w;//价值
int v;//容量
};
int main()
{
package bag[100];
int n, m;
int s[101][101];
cin >> n >> m;
for (int i = 0; i <= n; i++)
s[i][0] = 0;
for (int i = 0; i <= m; i++)
s[0][i] = 0;
//不知道为什么,一定要把上面的两个for语句写上,否则结果就会出现问题。
for (int i = 0; i < n; i++)
{
cin >> bag[i + 1].v >> bag[i + 1].w;
}
int d = min(bag[1].v, m);
for (int i = 0; i < d; i++)
s[1][i] = 0;
for (int i =d; i <= m; i++)
s[1][i] = bag[1].w;
for (int i = 2; i < n; i++)
{
for (int j = 0; j < bag[i].v; j++)
s[i][j] = s[i - 1][j];
for (int j = bag[i].v; j <= m; j++)
s[i][j] = max(s[i - 1][j], s[i - 1][j - bag[i].v] + bag[i].w);
//这里需要前面的初始化。当j=beg[i].v时,就是s[i-1][0]初始化。
}
if (bag[n].v > m)
s[n][m] = s[n - 1][m];
else
s[n][m] = max(s[n - 1][m], s[n - 1][m - bag[n].v] + bag[n].w);
printf("%d\n", s[n][m]);
system("pause");
return 0;
}
上面的思路的是先将第一行填好,然后下一行根据上一行:
简单说就是:s[i]]n] 取决于s[i-1][n],和s[i-1][n-w]。
用过之后就就可以丢掉了,这就是为什么优化可以用一维来替换二维。
下面是一维代码:
//这里描述将二维压缩成一维背包
#include "stdafx.h"
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
struct package
{
int w;
int v;
};
int main()
{
package bag[1000];
int goal[1001];
int n, c;
cin >> n >> c;
for (int i = 1; i <= n; i++)
{
cin >> bag[i].w >> bag[i].v;
}
goal[0] = 0;//这里就相当于一维数组的初始化,将0行0列的初始化为0;
memset(goal, 0, sizeof(goal));
for (int i = 1; i <= n; i++)
{
for (int j = c; j >= bag[i].w; j--)
goal[j] = max(goal[j], goal[j - bag[i].w] + bag[i].v);
}
//这里分析为什么可以将二维压缩成一维,主要是将前面的s[i-1],[i]去掉了。
//同时必须要倒序,因为后面的数组的值是根据前面的s[j-w],s[j],如果正序
//就会先填s[j-w],导致错误
printf("%d\n", goal[c]);
system("pause");
return 0;
}
用一维的过程和二维差不多,就是必须要倒序,原因如上。二维就是那种随便填的。