単一ナップザック問題
-
ソリューション要約しました:
-
まず、現在のフィットあれば記事、最初のn個の項目の最適な組み合わせと記事前のn-1の最良の組み合わせがある
ように。 -
第二に、場合電流が記事を満載しました。
-
仮説1:現在のスペースを予約し、現在の対応する記事、プラス記事前のn-1の最良の組み合わせの現在値は、物品の合計値である場合には、物品をロード。
-
仮定2:現在のアイテムがインストールされていないが、最初のn個のアイテムの最高の組み合わせと物品前のn-1の最良の組合せは同じです。
-
図1及び図2を最適な組み合わせの現在の値を想定より大きな値を選択するものとします。
-
-
-
最大値
//动态规划找到容量为r的背包所能装下的最大价值,n个物品
int maxValue(int n, int r) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= r; j++) {
if (weight[i] > j)
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
return dp[n][r];
}
//回溯找到背包里的物品是什么,i为编号,j为容量,n为物品数量,在object[]里存放
void fid(int i, int j, int n) {
if (i == 0) {
for (int k = 1; k <= n; k++)
if (object[k] == 1)
printf("%d ", k);
return;
}
if (dp[i][j] == dp[i - 1][j]) {
object[i] = 0;
fid(i - 1, j, n);
} else if (dp[i][j] == max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])) {
object[i] = 1;
fid(i - 1, j - weight[i], n);
}
}
const int maxn = 1e5 + 6;
//weight-->weight,value-->value,dp[编号][容量]-->前n个编号的在容量之内的最优价值
int weight[maxn], value[maxn], dp[10000][10000];
int object[maxn];
//动态规划找到容量为r的背包所能装下的最大价值,n个物品
int maxValue(int n, int r) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= r; j++) {
if (weight[i] > j)
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
return dp[n][r];
}
//回溯找到背包里的物品是什么,i为编号,j为容量,n为物品数量,在object[]里存放
void fid(int i, int j, int n) {
if (i == 0) {
for (int k = 1; k <= n; k++)
if (object[k] == 1)
printf("%d ", k);
return;
}
if (dp[i][j] == dp[i - 1][j]) {
object[i] = 0;
fid(i - 1, j, n);
} else if (dp[i][j] == max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])) {
object[i] = 1;
fid(i - 1, j - weight[i], n);
}
}
int main() {
int n, r, w, v;
scc(n, r);
for (int i = 1; i <= n; i++) {
scc(w, v);
weight[i] = w;
value[i] = v;
}
p(maxValue(n, r));
fid(n, r, n);
}
第二に、複数のナップザック問題
問題の概要:
バッグの容量バックパックの記事の、そこNUM [i]は番目の値value [i]は、重量重量[i]は、最高値を見つけます
コード:
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string>
#include<string.h>
#include<algorithm>
#include <vector>
#include <cctype>
#include <cstdlib>
using namespace std;
#define ll long long
#define il inline
#define oo 2147000000
#define sc(x) scanf("%d",&x)
#define scc(x, y) scanf("%d%d",&x,&y)
#define sccc(x, y, z) scanf("%d%d%d",&x,&y,&z)
#define p(x) printf("%d\n",x)
#define m(x, y) (x+y)>>1
#define l(x) x<<1
#define r(x) x<<1|1
#define MAX 1000000
int dp[MAX];//存储最后背包最大能存多少
int value[MAX], weight[MAX], num[MAX];//分别存的是物品的价值,每一个的重量以及数量
int bag;
void zeroOnePack(int weight, int value) {//01背包
int i;
for (i = bag; i >= weight; i--) {
dp[i] = max(dp[i], dp[i - weight] + value);
}
}
void completePack(int weight, int value) {//完全背包
int i;
for (i = weight; i <= bag; i++) {
dp[i] = max(dp[i], dp[i - weight] + value);
}
}
void multiplePack(int weight, int value, int num) {//多重背包
if (bag <= num * weight) {//如果总容量比这个物品的容量要小,那么这个物品可以直到取完,相当于完全背包
completePack(weight, value);
return;
} else {//否则就将多重背包转化为01背包
int k = 1;
while (k <= num) {
zeroOnePack(k * weight, k * value);
num = num - k;
k = 2 * k;//这里采用二进制思想
}
zeroOnePack(num * weight, num * value);
}
}
int main() {
int n;
while (~scc(bag, n)) {
int i, sum = 0;
for (i = 0; i < n; i++) {
scc(num[i],value[i]);//此题没有weight,可以认为weight=value
}
memset(dp, 0, sizeof(dp));
for (i = 0; i < n; i++) {
//调用多重背包,注意传参的时候分别是重量,价值和数量
multiplePack(value[i], value[i], num[i]);
}
p(dp[bag]);
}
return 0;
}