112 lines
3.6 KiB
Go
112 lines
3.6 KiB
Go
|
|
/*
|
|||
|
|
* @Author : huangzj
|
|||
|
|
* @Time : 2020/8/5 11:50
|
|||
|
|
* @Description:
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
package KnapsackOptimization
|
|||
|
|
|
|||
|
|
import "fmt"
|
|||
|
|
|
|||
|
|
type KnapsackSearchAnswer struct {
|
|||
|
|
BagCapacity int //背包的总容量上限
|
|||
|
|
BagItemList []*BagItem //背包道具列表
|
|||
|
|
ItemNum int //道具的数量
|
|||
|
|
|
|||
|
|
bestPath []int //最佳路径(怎么存放价值最高)
|
|||
|
|
currentBestPath []int //最佳路径(当前解)
|
|||
|
|
bestValue []int //每个容量最大价值
|
|||
|
|
currentValue int //当前价值
|
|||
|
|
currentWeight int //当前重量
|
|||
|
|
lastBestValue int //目前装载的最优价值
|
|||
|
|
surplusValue int //剩余道具价值
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func NewKnapsackSearchAnswer(bagItemList []*BagItem, bagCapacity int) *KnapsackSearchAnswer {
|
|||
|
|
if bagCapacity <= 0 {
|
|||
|
|
panic("背包总容量不能小于等于0")
|
|||
|
|
}
|
|||
|
|
answer := &KnapsackSearchAnswer{
|
|||
|
|
BagCapacity: bagCapacity,
|
|||
|
|
BagItemList: bagItemList,
|
|||
|
|
ItemNum: len(bagItemList),
|
|||
|
|
bestPath: make([]int, len(bagItemList)+1),
|
|||
|
|
currentBestPath: make([]int, len(bagItemList)+1),
|
|||
|
|
bestValue: make([]int, len(bagItemList)+1),
|
|||
|
|
}
|
|||
|
|
//初始化剩余道具价值等于所有道具总价值
|
|||
|
|
for _, r := range bagItemList {
|
|||
|
|
answer.surplusValue = answer.surplusValue + r.Value
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return answer
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//回溯法计算最佳路径和最大达到价值
|
|||
|
|
func (cmd *KnapsackSearchAnswer) DynamicPlanForBestValue() {
|
|||
|
|
cmd.initParam() //初始化第一个数组为空道具
|
|||
|
|
cmd.BackTrack(1) //从第一个道具开始进行路径搜索
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (cmd *KnapsackSearchAnswer) BackTrack(step int) {
|
|||
|
|
//遍历到最后一个道具
|
|||
|
|
if step > cmd.ItemNum {
|
|||
|
|
//如果当前总价值大于上一次装载的最佳价值
|
|||
|
|
if cmd.currentValue > cmd.lastBestValue {
|
|||
|
|
//最终的最佳路径用当前最佳路径来替换
|
|||
|
|
for i := 1; i <= cmd.ItemNum; i++ {
|
|||
|
|
cmd.bestPath[i] = cmd.currentBestPath[i]
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
cmd.lastBestValue = cmd.currentValue
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//装入该道具之后,剩余的价值要减去当前道具的价值
|
|||
|
|
cmd.surplusValue = cmd.surplusValue - cmd.BagItemList[step].Value
|
|||
|
|
//当前道具的总重量没有超重
|
|||
|
|
if cmd.currentWeight+cmd.BagItemList[step].Weight <= cmd.BagCapacity {
|
|||
|
|
|
|||
|
|
cmd.currentBestPath[step] = 1 //当前道具选中了,设置为1
|
|||
|
|
cmd.currentValue = cmd.currentValue + cmd.BagItemList[step].Value //计算当前价值
|
|||
|
|
cmd.currentWeight = cmd.currentWeight + cmd.BagItemList[step].Weight //计算当前价值
|
|||
|
|
|
|||
|
|
cmd.BackTrack(step + 1) //继续遍历下一个道具
|
|||
|
|
|
|||
|
|
cmd.currentValue = cmd.currentValue - cmd.BagItemList[step].Value //遍历完成要恢复成原来的价值
|
|||
|
|
cmd.currentWeight = cmd.currentWeight - cmd.BagItemList[step].Weight //遍历完成要恢复成原来的重量
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//这边是剪枝的操作,如果剩余价值加上当前价值会超过上一次的最佳价值,那么就要往右子树遍历,否则不操作.
|
|||
|
|
if cmd.surplusValue+cmd.currentValue > cmd.lastBestValue {
|
|||
|
|
cmd.currentBestPath[step] = 0 //当前路径置为0,不选择该位置
|
|||
|
|
cmd.BackTrack(step + 1)
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
cmd.surplusValue = cmd.surplusValue + cmd.BagItemList[step].Value
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//输出最佳路径解
|
|||
|
|
func (cmd *KnapsackSearchAnswer) PrintBestSearchPath() {
|
|||
|
|
|
|||
|
|
for index, r := range cmd.bestPath {
|
|||
|
|
if r == 1 {
|
|||
|
|
fmt.Print(" ")
|
|||
|
|
fmt.Println(fmt.Sprintf("道具的价值是:%d,道具的重量是%d", cmd.BagItemList[index].Value, cmd.BagItemList[index].Weight))
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (cmd *KnapsackSearchAnswer) initParam() {
|
|||
|
|
itemList := make([]*BagItem, 0)
|
|||
|
|
itemList = append(itemList, &BagItem{})
|
|||
|
|
itemList = append(itemList, cmd.BagItemList...)
|
|||
|
|
cmd.BagItemList = itemList
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (cmd *KnapsackSearchAnswer) BestValue() int {
|
|||
|
|
return cmd.lastBestValue
|
|||
|
|
}
|