问题描述
01背包问题
问题分析
- 动态规划法分析:1.划分子问题,2.得出子问题的递推公式,3.填表
- 划分子问题
- 用数组V[n][n]存储价值和重量关系,行表示物体,列表示重量
- 第0行和第0列设置为0,没有物体的时候价值没0,重量为0的时候物体无论多少价值也为0
- 如果第i个物体重量小于当前总重量j,则取前i-1和第i个物体组合的最优值,否则该物体不可以放进背包,取前i-1个物体的最优价值(例如装入当前物体,则剩余重量用来装前面剩余物体的最优装法得到当前最优价值,得出max{V(i-1, j), V(i-1, j-wi)+vi } ;不装入当前物体,则以目前重量装前面所有物体的最优法),得出V(i-1, j)。
- 递推公式
- 不装入背包时:V(i-1, j) j < wi
- 装入背包时:max{V(i-1, j), V(i-1, j-wi)+vi } j >= wi
- V(i-1, j-wi)+vi 表示用当前值和子问题的解结合,取最优
- 填表,计算每个重量级别的时候,最佳的存放方式,
- 因为装完一个物体后,剩余的重量在前面物体的选择中的最优解就是当前重量的最优解
- 比如当前重量为7的时候,选择第四个物体(5,4)是,重量5小于总重量7,因此可选
- 选择后v=4,剩余重量=7-5=2,物体4之前的重量2的最佳选择是v=6的时候
- 此时选择物体四的价值是v=4+6=10 > 9 因为,此条件下v=10最佳,直到重量10,物体6都处理完毕即可得出最优解
算法实现
#include<iostream>
using namespace std;
struct Node {
int value;
int weight;
};
// 物体,长度
void packageHander(Node arr[], int n, int c) {
int V[n][c+1], i;
// 第0行和第0列设置为0,没有物体的时候价值没0,重量3为0的时候物体无论多少价值也为0
for (i = 0; i < n; i++) {
V[i][0] = 0;
}
for (i = 0; i <= c; i++) {
V[0][i] = 0;
}
for (i = 1; i < n; i++) {
// 重量从1到c
for (int j = 1; j <= c; j++) {
// 重量小于目前总量
// 如果第i个物体重量小于当前总重量j,则取前i-1和第i个物体组合的最优值,否则该物体不可以放进背包,取前i-1个物体的最优价值
if (arr[i-1].weight <= j) {
V[i][j] = max(V[i-1][j], V[i-1][j-arr[i-1].weight]+arr[i-1].value);
} else {
V[i][j] = V[i-1][j];
}
}
}
for (i = 0; i <= c; i++) {
cout<<i<<"\t";
}
cout<<endl;
for (i = 0; i < n; i++) {
for (int j = 0; j <= c; j++) {
cout<<V[i][j]<<"\t";
}
cout<<endl;
}
int j = 0;
// 如果当前值比前一个值大,说明被取了,就取当前值,然后减去重量,重量作为列
for ( i=n, j=c; i>0; i--) {
if (V[i][j] > V[i-1][j]) {
x[i-1] = 1;
j = j - arr[i-1].weight;
} else {
x[i-1] = 0;
}
}
cout<<"选取方案为";
for (i = 0; i<n-1; i++) {
cout<<x[i]<<" ";
}
cout<<endl;
}
int main() {
int n = 6;
Node a[n];
a[0].value = 6;
a[0].weight = 2;
a[1].value = 3;
a[1].weight = 2;
a[2].value = 5;
a[2].weight = 6;
a[3].value = 4;
a[3].weight = 5;
a[4].value = 6;
a[4].weight = 4;
for (int i = 0; i < n-1; i++) {
cout<<"val"<<a[i].value<<"weight"<<a[i].weight<<endl;
}
packageHander(a, n, 10);
return 0;
}