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

定义

在限定条件下,如何从众多物品中选出收益最高的几件物品,这样的问题就称为背包问题。

举个简单的例子,帕朵菲莉丝进货的时候有一个可以装 15kg 的背包,一共有 5 个物品重量为一个数组 [1, 2, 1, 12, 4],每个物品的价值也为一个数组 [5, 8, 5, 50, 15],可以购买商品的一部分(可再分),如何使每次进货收益最高?
啊啊啊啊啊啊啊!帕朵菲莉丝!猫猫!米哈游你坏事做尽!

思路

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

选择收益最大的商品可以将收益放在一个数组当中,将数组进行排序,同时将对应的物品重量数组、物品价值数组排序,并每次拿到最大的数组。

贪心算法,贪心贪心,就贪心在每次都要拿最好最厉害的。根据这个思想很容易理解上面的文字

图示

我们假定一个数组(该数组只是便于理解而假定出来的),用来存放物品的重量weight、物品的价值price以及物品的利益profit
在这里插入图片描述

根据刚刚的贪心算法思想,贪心一点每次都拿最大最好的,那么我们怎么获取最大最好的呢?答案是先对这个假定的数组根据物品利益profit进行排序。最终得到的数组顺序:

此时依次将利益最大的物品放入背包:
在这里插入图片描述
在这里插入图片描述

最后一个元素比较特殊,背包无法将全部物品装入,只能装入一部分,而题目是可以让我们对物品进行分割的,所以可以取20重量的物品放进背包,而价值也应该相应减少到对应价值,具体见图示
在这里插入图片描述
背包容量为0,说明装不下了,再贪心也装不了,那就结束,返回结果result为最终收益。

具体代码:

import { Component, Vue } from "vue-property-decorator";

@Component({
  components: {},
})
export default class PartPack extends Vue {
  // 包的容量
  pack = 0;
  // 物品重量
  weight = [];
  // 物品价值
  price = [];
  // 物品对应收益的数组
  profit = [];
  // 最终结果
  result = 0;

  // 根据收益进行排序
  sort(weight, price) {
    let length = weight.length;
    let temp = 0;
    // 获取收益数组
    for (let i = 0; i < length; i++) {
      this.profit[i] = weight[i] / price[i];
    }
    // 冒泡排序,将weight[]、price[]、profit[]三个数组进行排序
    for (let i = 0; i < length; i++) {
      for (let j = 1; j < length - i; j++) {
        if (this.profit[j] < this.profit[j - 1]) {
       	  // 这三段代码就是刚刚说的假定的数组
          temp = this.profit[j - 1];
          this.profit[j - 1] = this.profit[j];
          this.profit[j] = temp;

          temp = weight[j - 1];
          weight[j - 1] = weight[j];
          weight[j] = temp;

          temp = price[j - 1];
          price[j - 1] = price[j];
          price[j] = temp;
        }
      }
    }
  }

  partPack(weight, price, pack) {
    let result = 0;
    let i = 0;

    // 排序
    this.sort(weight, price);

    while (pack > 0) {
      // 如果能装下这个物品,就装入整个物品,如果装不下了, 就装背包剩下能装的
      let temp = pack > weight[i] ? weight[i] : pack;
      // 计算今天收入
      result += (temp / weight[i]) * price[i];
      // 背包被占了多少
      pack -= temp;
      // 后台打印每个物品赚多少
      console.log(
        "这次第" +
          (i + 1) +
          "个物品装进了" +
          ((temp / weight[i]) * 100).toFixed(2) +
          "%,赚了" +
          (temp / weight[i]) * price[i] +
          "个银币!"
      );
      i++;
    }
    return result;
  }

  display() {
    this.pack = 50;
    this.weight = [10, 20, 30];
    this.price = [60, 140, 120];
    this.result = this.partPack(this.weight, this.price, this.pack);
    console.log("罐头!咱这次进货一共赚了" + this.result + "个银币!");
  }

  mounted() {
    this.display();
  }
}

后台输出:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值