【算法】贪心算法解决部分背包问题

// 部分背包问题
// 在限定条件下,如何从众多物品中选出收益最高的几件物品,这样的问题就称为背包问题。
// 举个简单的例子,商店的货架上摆放着不同重量和价值的商品,一个小偷在商店行窃,
// 他携带的背包只能装固定重量的商品,选择哪些商品才能获得最大的收益呢?这个问题就属于背包问题,
// 限定条件是背包的承重,最终目标是令背包中存放的物品的总收益最高。

// 根据不同的限定条件,背包问题还可以有更细致的划分:
//   0-1背包问题:每件物品都不可再分,要么整个装入背包,要么放弃,不允许出现类似“将物品的 1/3 装入背包”的情况;
//   部分背包问题:每件物品是可再分的,即允许将某件物品的一部分(例如 1/3)放入背包;
//   完全背包问题:挑选物品时,每件物品可以选择多个,也就是说不限物品的数量。
//   多重背包问题:每件物品的数量是有严格规定的,比如物品 A 有 2 件,物品 B 有 3 件。
//   不同的背包问题,对应的解决方案也不相同。本节我们给大家讲解,如何用贪心算法解决部分背包问题。

// 假设商店中有 3 种商品,它们各自的重量和收益是:
// 商品 1:重量 10 斤,收益 60 元;
// 商品 2:重量 20 斤,收益 100 元;
// 商品 3:重量 30 斤,收益 120 元。
//
// 对于每件商品,顾客可以购买商品的一部分(可再分)。一个小偷想到商店行窃,他的背包最多只能装 50 斤的商品,
// 如何选择才能获得最大的收益呢?

// 贪心算法解决此问题的思路是:计算每个商品的收益率(收益/重量),优先选择收益率最大的商品,直至所选商品的总重量达到 50 斤。

package main

import (
	"math"
	"fmt"
)

// 根据收益率,对记录的商品进行从大到小排序
func sort(w [] float64, p []float64) {
	// 用v[]存商品的收益率
	v := make([]float64, len(w))

	for i := 0; i < len(w); i++ {
		v[i] = p[i] / w[i]
		fmt.Printf("商品%f收益率是:%f\n", p[i], v[i])
	}
	fmt.Printf("排序前的收益率是:%f\n", v)
	fmt.Printf("排序前的商品总重量是:%f\n", w)
	fmt.Printf("排序前的商品总价值是:%f\n", p)

	// 根据v数组记录的各个商品收益率的大小,同时对w和p数组进行排序
	// 方便后面根据收益率获取到各个商品的信息
	for i := 0; i < len(w); i++ {
		for j := i + 1; j < len(w); j++ {
			if v[i] < v[j] {
				v[i], v[j] = v[j], v[i]
				w[i], w[j] = w[j], w[i]
				p[i], p[j] = p[j], p[i]
			}
		}
	}
	fmt.Printf("排序后的收益率是v[i]:%f\n", v)
	fmt.Printf("排序后的商品总重量是w[i]:%f\n", w)
	fmt.Printf("排序后的商品总价值是p[i]:%f\n", p)
}

// 贪心算法解决部分背包问题
// w记录各个商品的总重量,p记录各个商品的总价值,result记录各个商品装入背包的比例
// W背包的重量

func fractionalKnaspack(w []float64, p []float64, result []float64, W float64) {
	// 定义temp为每次能装入背包的重量
	var temp float64 = 0
	sort(w, p)
	for i := 0; ; {
		fmt.Printf("各个商品总重量:%f,背包剩余的总重量:%f\n", w[i], W)
		// 获取当前还能装入背包的重量
		temp = math.Min(w[i], W)
		fmt.Printf("装入背包重量:%f\n", temp)
		// 获取装入背包的商品的比例
		result[i] = temp / w[i]
		fmt.Printf("商品装入比例:%f\n", result[i])
		// 背包剩余的总重量
		W -= temp
		i++
		fmt.Printf("背包剩余总重量:%f\n", W)

		if W <= 0 {
			break
		}
	}
	fmt.Printf("最终装入背包的收益率result[i]是:%f\n", result)
}

func main() {
	var values float64 = 0
	w := []float64{10, 30, 20}
	p := []float64{60, 100, 120}
	result := make([]float64, len(w))
	fractionalKnaspack(w, p, result, 50)

	for i := 0; i < len(w); i++ {
		if result[i] == 1 {
			fmt.Printf("总重量为%f,总价值为%f的商品全部转入\n", w[i], p[i])
			values += p[i]
		} else if result[i] == 0 {
			fmt.Printf("总重量为%f,总价值为%f的商品不装\n", w[i], p[i])
		} else {
			fmt.Printf("总重量为%f,总价值为%f的商品转入率%f\n", w[i], p[i], result[i]*100)
			values += p[i] * result[i]
		}
	}
	fmt.Printf("最终收获的商品价值为%f", values)
}

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值