Go语言数据结构和算法(三十九)动态规划背包问题

7 阅读4分钟

背包问题是计算机科学和数学中著名的优化问题.该问题涉及选择一组具有最大总价

值的项目.并受项目最大重量约束.

1.步骤:

1.1定义问题:

明确定义问题并确定目标函数和约束条件.

1.2输入数据:

输入所有可装入背包的物品的重量和价值.

1.3指定问题:

将问题定制为数学优化问题.目标是最大优化背包中物品的总价值.受物品重量不能超

过背包容量的约束.

1.4选择算法:

选择一种算法类解决背包问题.最常见的算法是动态规划算法和贪心算法.

1.5实现算法:

用自己选择的编程语言实现所选算法.

1.6测试解决方案:

通过在不同的测试用例上运行算法来测试解决方案.并验证解决方案是否满足问题的

要求.

1.7优化解决问题方案:

如有必要.通过调整算法或更改输入数据来优化解决方案.

1.8输出解:

输出最终解.应该是不超过重量限制的情况下.总价值最大化装入背包的物品的集合.

2.使用场景:

投资组合优化:

投资者经常面临如何分配资产以获得最大回报同时最小化风险的问题.

资源分配:

再制造工厂中.有不同的机器可以执行各种任务.每台机器有不同的生产效率.每个任务

都有不同的处理时间和价值.要求将任务分配给机器.以在给定的时间限制最大化完成

任务的总价值.

装箱:

假设有一个仓库.有一份不同尺寸的物品清单.需要将它们装入不同的容器中.要求尽量

减少所需容器的数量.同时确保所有物品都适合每个容器给定的容量.

3.实现:

3.1方法:

package data

// 返回包中可以放置的最大值.
func Knapsack(W int, weights, values []int) int {
    //数组的长度.
    n := len(weights)

    //创建一个n+1行.w+1列的二维切片.
    dp := make([][]int, n+1)

    for i := range dp {
       dp[i] = make([]int, W+1)
    }

    //动态规划填充切片.
    for i := 1; i <= n; i++ {
       for w := 1; w <= W; w++ {
          if weights[i-1] > w {
             //如果加入第i件物品后的总重量大于最大重量w.则第i件不能放入背包.
             dp[i][w] = dp[i-1][w]
          } else {
             dp[i][w] = maxSack(dp[i-1][w], dp[i-1][w-weights[i-1]]+values[i-1])
          }
       }
    }
    //使用所有物品和最大重量w可以得到的最大值是解决方案.
    return dp[n][W]
}

func maxSack(a, b int) int {
    if a > b {
       return a
    }
    return b
}

3.2main方法:

func main() {
	//背包最大重量.
	w := 10
	//放在背包中物品重量.
	weights := []int{2, 3, 4, 5}
	//放在背包中物品的价值.
	values := []int{3, 4, 5, 6}
	knapsack := data.Knapsack(w, weights, values)
	fmt.Println(knapsack)
}

4.实战:

给定一个整数数组array.确认是否可以将数组分成两个子集.使得两个子集中的元素

之和相等.可以则返回true.否则返回false.

4.1方法:

func CarPartition(array []int) bool {
	//计算输入切片长度.
	n := len(array)
	//计算所有切片元素和.
	sum := 0
	for _, num := range array {
		sum += num
	}
	//如果和为奇数.无法将输入切片划分为两个相等的子集.
	if sum%2 != 0 {
		return false
	}
	//计算每个子集的目标总和.即总和一半.
	target := sum / 2
	//初始化长度为target+1的布尔切片.并将第一个元素置为true.
	dp := make([]bool, target+1)
	dp[0] = true
	//迭代输入切片.对于每个元素.相反的顺序迭代切片.
	//如果dp[j]或dp[j-array[i]为true.则将每个元素dp[j]更新为真true.
	for i := 0; i < n; i++ {
		for j := target; j >= array[i]; j-- {
			dp[j] = dp[j] || dp[j-array[i]]
		}
	}
	//返回布尔切片最后一个元素.表示是否可以创建总和等于目标的子集.
	return dp[target]
}

4.2main方法:

```
func main() {
    array := []int{1, 5, 11, 5}
    partition := data.CarPartition(array)
    fmt.Println(partition)
}
```

一曲不到江南.一春难到四月.





如果大家喜欢我的分享的话.可以关注我的微信公众号

念何架构之路