feat(Go-Tool): 添加求背包问题最优解三种方式(KnapsackOptimizationUtil.go)及其单测类,添加求背包问题最优解过程路径(KnapsackSearchAnswerUtil.go)及其单测类.添加背包问题的readme相关说明

This commit is contained in:
huangzj
2020-08-06 11:37:49 +08:00
parent 223baa60ba
commit c1f291ee79
11 changed files with 388 additions and 0 deletions
@@ -0,0 +1,111 @@
/*
* @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
}