2020-08-06 11:37:49 +08:00
|
|
|
|
/*
|
|
|
|
|
|
* @Author : huangzj
|
|
|
|
|
|
* @Time : 2020/7/31 15:35
|
|
|
|
|
|
* @Description:背包最优问题工具类
|
|
|
|
|
|
* 基本场景:给定n个重量为w1w 1,w2w 2 ,w3w 3 ,…,wnw n ,价值为v1v 1 ,v2v 2 ,v3v 3 ,…,vnv n 的物品和容量为CC的背包,求这个物品中一个最有价值的子集,使得在满足背包的容量的前提下,包内的总价值最大
|
|
|
|
|
|
* 参考地址:https://blog.csdn.net/chanmufeng/article/details/82955730
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2020-08-18 17:29:42 +08:00
|
|
|
|
package knapsackOptimization
|
2020-08-06 11:37:49 +08:00
|
|
|
|
|
|
|
|
|
|
type KnapsackOptimization struct {
|
|
|
|
|
|
BagCapacity int //背包的总容量上限
|
|
|
|
|
|
BagItemList []*BagItem //背包道具列表
|
|
|
|
|
|
ItemNum int //道具的数量
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func NewKnapsackOptimization(bagItemList []*BagItem, bagCapacity int) *KnapsackOptimization {
|
|
|
|
|
|
if bagCapacity <= 0 {
|
|
|
|
|
|
panic("背包总容量不能小于等于0")
|
|
|
|
|
|
}
|
|
|
|
|
|
return &KnapsackOptimization{
|
|
|
|
|
|
BagCapacity: bagCapacity,
|
|
|
|
|
|
BagItemList: bagItemList,
|
|
|
|
|
|
ItemNum: len(bagItemList),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//通过递归的方式解决上述基本场景,这种方式效率比较低下
|
|
|
|
|
|
func (cmd *KnapsackOptimization) OptimizePackageByRecursion() int {
|
|
|
|
|
|
return cmd.knapsackRecursion(cmd.BagItemList, len(cmd.BagItemList)-1, cmd.BagCapacity)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (cmd *KnapsackOptimization) knapsackRecursion(bagItemList []*BagItem, index, capacity int) int {
|
|
|
|
|
|
if index < 0 || capacity <= 0 {
|
|
|
|
|
|
return 0
|
|
|
|
|
|
}
|
|
|
|
|
|
res := cmd.knapsackRecursion(bagItemList, index-1, capacity) //不放第index个物品所得价值
|
|
|
|
|
|
//放第index个物品所得价值(前提是:第index个物品可以放得下)
|
|
|
|
|
|
if bagItemList[index].Weight <= capacity {
|
|
|
|
|
|
res = max(res, bagItemList[index].Value+cmd.knapsackRecursion(bagItemList, index-1, capacity-bagItemList[index].Weight))
|
|
|
|
|
|
}
|
|
|
|
|
|
return res
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (cmd *KnapsackOptimization) KnapsackCycle() int {
|
|
|
|
|
|
dynamicPlan := cmd.initKnapsackParam() //初始化参数,这边通过动态规划的方式处理,需要一个辅助行和辅助列
|
|
|
|
|
|
//循环所有的道具,进行动态规划二维数组的组装.
|
|
|
|
|
|
for i := 1; i <= cmd.ItemNum; i++ {
|
|
|
|
|
|
for j := 1; j <= cmd.BagCapacity; j++ {
|
|
|
|
|
|
//如果背包重量不够,则不能装下这个道具
|
|
|
|
|
|
if j < cmd.BagItemList[i].Weight {
|
|
|
|
|
|
dynamicPlan[i][j] = dynamicPlan[i-1][j]
|
|
|
|
|
|
} else {
|
|
|
|
|
|
//如果背包重量足够的话,判断装入这个道具价值更高,还是不装这个道具价值更高
|
|
|
|
|
|
dynamicPlan[i][j] = max(dynamicPlan[i-1][j], dynamicPlan[i-1][j-cmd.BagItemList[i].Weight]+cmd.BagItemList[i].Value)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return dynamicPlan[len(cmd.BagItemList)-1][cmd.BagCapacity-1]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//通过一维数组实现背包求解
|
|
|
|
|
|
func (cmd *KnapsackOptimization) KnapsackCycleSimple() int {
|
|
|
|
|
|
dynamicPlan := cmd.initKnapsackParamSimple()
|
|
|
|
|
|
for i := 1; i <= cmd.ItemNum; i++ {
|
|
|
|
|
|
for j := cmd.BagCapacity; j >= cmd.BagItemList[i].Weight; j-- {
|
|
|
|
|
|
dynamicPlan[j] = max(dynamicPlan[j], dynamicPlan[j-cmd.BagItemList[i].Weight]+cmd.BagItemList[i].Value)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return dynamicPlan[cmd.BagCapacity]
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (cmd *KnapsackOptimization) initKnapsackParamSimple() []int {
|
|
|
|
|
|
itemList := make([]*BagItem, 0)
|
|
|
|
|
|
itemList = append(itemList, &BagItem{})
|
|
|
|
|
|
itemList = append(itemList, cmd.BagItemList...)
|
|
|
|
|
|
cmd.BagItemList = itemList
|
|
|
|
|
|
return make([]int, cmd.BagCapacity+1)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//这里需要组成一个辅助数组去判断动态规划的实现
|
|
|
|
|
|
func (cmd *KnapsackOptimization) initKnapsackParam() [][]int {
|
|
|
|
|
|
itemList := make([]*BagItem, 0)
|
|
|
|
|
|
itemList = append(itemList, &BagItem{})
|
|
|
|
|
|
itemList = append(itemList, cmd.BagItemList...)
|
|
|
|
|
|
cmd.BagItemList = itemList
|
|
|
|
|
|
//初始化数组
|
|
|
|
|
|
dynamicPlan := make([][]int, len(cmd.BagItemList))
|
|
|
|
|
|
for i := 0; i <= cmd.ItemNum; i++ {
|
|
|
|
|
|
dynamicPlan[i] = make([]int, cmd.BagCapacity+1)
|
|
|
|
|
|
}
|
|
|
|
|
|
return dynamicPlan
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func max(compareNum, otherCompareNum int) int {
|
|
|
|
|
|
if compareNum > otherCompareNum {
|
|
|
|
|
|
return compareNum
|
|
|
|
|
|
}
|
|
|
|
|
|
return otherCompareNum
|
|
|
|
|
|
}
|