# g10guang/g10guang.github.io

Switch branches/tags
Nothing to show
Fetching contributors…
Cannot retrieve contributors at this time
375 lines (283 sloc) 12 KB
layout title date categories
post

2018-09-22 20:00:05 +0800

1. 0-1 背包
2. 多重背包
3. 完全背包
4. 多维背包
5. 塞满背包

# Main

1. 问题能够分解为子问题
2. 全局最优依赖于局部最优，每次求局部最优能够求得全局最优
3. 解空间有重叠，能够通过存储局部解，减少冗余计算
4. 局部解不会失效

```def fibonacci():
mark = {1: 1, 2: 1}
n = 1
while True:
if n in mark:
ret = mark[n]
else:
ret = mark[n - 1] + mark[n - 2]
mark[n] = ret
yield ret
n += 1```

## 0-1 背包

``````f(i, v) = max{
f(i - 1, v),
f(i - 1, v - w[i]) + p[i] if v >= w[i] else 0
}
``````

```func zeroOneKnapsack(w, p []int, N, W int) int {
f := make([][]int, N+1)
for i := 0; i <= N; i++ {
f[i] = make([]int, W+1)
}

for i := 1; i <= N; i++ {
for v := 1; v <= W; v++ {
if w[i] > v {
f[i][v] = f[i-1][v]
} else {
f[i][v] = max(f[i-1][v], f[i-1][v-w[i-1]]+p[i-1])
}
}
}

return f[N][W]
}```

0 1 2 3 4 5 6 7
0 0 0 0 0 0 0 0 0
1 0
2 0
3 0
4 0

0 1 2 3 4 5 6 7
0 0 0 0 0 0 0 0 0
1 0 0 4 4 4 4 4 4
2 0 0 4 4 4 7 7 7
3 0 5 5 9 9 9 12 12
4 0 5 5 9 9 9 12 12

### 数组空间缩小为 O(W)

``````f(i, v) = max{
f(i - 1, v),
f(i - 1, v - w[i]) + p[i] if v >= w[i] else 0
}
``````

`f(i, v)` 只依赖于 `f(i - 1, v)``f(i - 1, v - w[i])` 两个解，也就是求解 `f(i, 0...W)` 只需要依赖于 `f(i - 1, 0...W)`，可把存储空间降到 `O(N)`

```func zeroOneKnapsackSpaceAdvance(w, p []int, N, W int) int {
f := make([]int, W+1)
for i := 1; i <= N; i++ {
for v := W; v > 0 && w[i] <= v; v-- {
// f(i, v) = max{ f(i - 1, v), f(i - 1, v - w[i]) + p[i]}
f[v] = max(f[v-w[i]]+p[i], f[v])
}
}
return f[W]
}```

## 多重背包

``````f(i, v) = max(f(i - 1, v - k * w[i]) for k := 0...n[i] if v >= k * w[i])
``````
```func multiKnapsack(w, p, n []int, N, W int) int {
f := make([][]int, N+1)
for i := 0; i <= N; i++ {
f[i] = make([]int, W+1)
}
for i := 1; i <= N; i++ {
for v := 1; v <= W; v++ {
for k := 0; k <= n[i]; k++ {
if v >= k*w[i] {
f[i][v] = max(f[i-1][v], f[i-1][v-k*w[i]]+k*p[i])
} else {
f[i][v] = f[i - 1][v]
}
}
}
}
return f[N][W]
}```

```func multiKnapsackSpaceAdvance(w, p, n []int, N, W int) int {
f := make([]int, W + 1)
for i := 0; i <= N; i++ {
for v := W; v > 0; v-- {
for k := 1; k <= n[i] && v >= k * w[i]; k++ {
f[v] = max(f[v], f[v - k * w[i]] + k * p[i])
}
}
}
return f[W]
}```

## 完全背包

```func comleteKnapsack(w, p []int, N, W int) int {
f := make([]int, W+1)
for v := 1; v <= W; v++ {
for i := range w {
if v >= w[i] {
f[v] = max(f[v], f[v-w[i]]+p[i])
}
}
}
return f[W]
}```

Leetcode 322. Coin Change

Leetcode 377. Combination Sum IV

## 多维背包

``````f(i, v, y) = max {
f(i - 1, v, y),
f(i - 1, v - w[i], y - s[i]) if v >= w[i] and y >= s[i] else 0
}
``````

```func multiDimensionKnapsack(w, p, s []int, N, W, S int) int {
f := make([][][]int, N+1)
for i := 0; i <= N; i++ {
f[i] = make([][]int, W+1)
for j := 0; j <= S; j++ {
f[i][j] = make([]int, S+1)
}
}
for i := 1; i <= N; i++ {
for v := 0; v <= W; v++ {
for y := 0; y <= S; y++ {
if v >= w[i] && y >= s[i] {
f[i][v][y] = max(f[i-1][v][y], f[i-1][v-w[i]][y-s[i]])
} else {
f[i][v][y] = f[i-1][v][y]
}
}
}
}
return f[N][W][S]
}```

```func multiDimensionKnapsackSpaceAdvance(w, p, s []int, N, W, S int) int {
f := make([][]int, W+1)
for i := 0; i <= W; i++ {
f[i] = make([]int, S+1)
}
for i := 1; i <= N; i++ {
for v := W; v > 0 && v >= w[i]; v-- {
for y := S; y > 0 && y >= s[i]; y-- {
f[v][y] = max(f[v][y], f[v-w[i]][y-s[i]]+p[i])
}
}
}
return f[W][S]
}```

Leetcode 474. Ones and Zeroes

## 塞满背包

``````f(i) = f(i) || f(i - v)
``````
```func fullKnapsack(w []int, N, W int) bool {
// f mark every value is reachable or not.
f := make([]bool, W+1)
// 0 can be reach always
f[0] = true
// make sure every number will be used just once.
for _, v := range w {
// loop from W to 0
// if loop from 0 to W, every f[k * v] will be set true.
for t := W; t > 0 && t >= v; t-- {
f[t] = f[t] || f[t-v]
}
}
// judge
return f[W]
}```

dp 的值除了可以记录是否可达（true / false）外，还能够记录到达该顶点的路径数。

``````f(i) = f(i) + f(i - v)
``````
```func knapsackWaysCnt(w []int, N, W int) int {
f := make([]int, W+1)
f[0] = 1
for _, v := range w {
for t := W; t >= v; t-- {
f[t] += f[t-v]
}
}
return f[W]
}```

Leetcode 416. Partition Equal Subset Sum

Leetcode 494. Target Sum

Leetcode 139. Word Break