01背包
题目
2. 01背包问题 - AcWing题库
有N件物品和一个容量是V的背包。每件物品只能使用一次。
第i件物品的体积是vi,价值是wi。
求解: 将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
思路
https://alchemist-al.com/algorithms/knapsack-problem
状态转移方程
f(i, v) 表示前 i 件物品恰放入一个容量为 v 的背包可以获得的最大价值。
python3解法
方法一:二维数组
N, V = map(int, input().split())
goods = []
for i in range (N):
goods.append([int(i) for i in input().split()])
dp = [[0 for i in range (V+1) ] for j in range (N+1)]
for i in range (1, N+1):
row = dp[i]
[v, w] = goods[i - 1]
for j in range (1, V+1):
if j >= v:
row[j] = max(dp[i-1][j], dp[i-1][j-v] + w)
else:
row[j] = dp[i-1][j]
print(dp[N][V])
方法二:一维数组
N, V = map(int, input().split())
goods = []
for i in range (N):
goods.append([int(i) for i in input().split()])
dp = [0 for i in range (V+1) ]
for i in range (1, N+1):
[v, w] = goods[i - 1]
for j in range (V, 0, -1):
if j >= v:
dp[j] = max(dp[j], dp[j-v] + w)
print(dp[V])
golang解法
方法一:二维数组
package main
import (
"fmt"
"math"
)
func main() {
var N, V int
fmt.Scanf("%d %d", &N, &V)
v := make([]int, N)
w := make([]int, N)
for i:=0; i<N; i++ {
fmt.Scanf("%d %d", &v[i], &w[i])
}
dp := make([][]int, N+1)
for i:=0; i<=N; i++ {
dp[i] = make([]int, V+1)
}
for i:=1; i<=N; i++ {
vi := v[i-1]
wi := w[i-1]
for j:=1; j<=V; j++ {
if j >= vi {
dp[i][j] = int(math.Max(float64(dp[i-1][j]), float64(dp[i-1][j-vi] + wi)))
} else {
dp[i][j] = dp[i-1][j]
}
}
}
fmt.Println(dp[N][V])
}
方法二:一维数组
package main
import (
"fmt"
"math"
)
func main() {
var N, V int
fmt.Scanf("%d %d", &N, &V)
v := make([]int, N)
w := make([]int, N)
for i:=0; i<N; i++ {
fmt.Scanf("%d %d", &v[i], &w[i])
}
dp := make([]int, V+1)
for i:=1; i<=N; i++ {
vi := v[i-1]
wi := w[i-1]
for j:=V; j>=1; j-- {
if j >= vi {
dp[j] = int(math.Max(float64(dp[j]), float64(dp[j-vi] + wi)))
}
}
}
fmt.Println(dp[V])
}
c语言解法
方法一:二维数组
#include <stdio.h>
#define LENGTH 1001
int main() {
int N, V;
scanf("%d %d", &N, &V);
int v[LENGTH], w[LENGTH];
for (int i=0; i<N; i++) {
scanf("%d %d", &v[i], &w[i]);
}
int dp[LENGTH][LENGTH];
for (int i=1; i<=N; i++) {
int vi = v[i-1];
int wi = w[i-1];
for (int j=1; j<=V; j++) {
if (j >= vi && dp[i-1][j] < dp[i-1][j-vi] + wi) {
dp[i][j] = dp[i-1][j-vi] + wi;
} else {
dp[i][j] = dp[i-1][j];
}
}
}
printf("%d", dp[N][V]);
return 0;
}
方法二:一维数组
#include <stdio.h>
#define LENGTH 1001
int main() {
int N, V;
scanf("%d %d", &N, &V);
int v[LENGTH], w[LENGTH];
for (int i=0; i<N; i++) {
scanf("%d %d", &v[i], &w[i]);
}
int dp[LENGTH];
for (int i=0; i<=V; i++) {
dp[i] = 0;
}
for (int i=1; i<=N; i++) {
int vi = v[i-1];
int wi = w[i-1];
for (int j=V; j>=1; j--) {
if (j >= vi && dp[j] < dp[j-vi] + wi) {
dp[j] = dp[j-vi] + wi;
}
}
}
printf("%d", dp[V]);
return 0;
}