背包问题解决公司零食采购(贪心+冒泡+动态)

  • 问题描述
    • 公司需要采购零食,那么在有限金额的情况下,如何选择零食种类及每一种的数量,成为了每次都需要考虑的问题,那么有没有一种可以自动生成零食采购清单的程序,来解救公司选择困难症的采购小姐姐。
    • 输入:零食名称的数组,以及对应的单价,以及一个零食偏好度的数组,还有总额。
    • 输出:在照顾到零食偏好度的情况下,尽可能的花完预算,输出采购的零食种类、采购量及实际花费。
  • 源码零食购买分配
  • 输入参数
/**
* @params foodName 零食名称
* @params prices   零食价格
* @params lover    零食喜好度(用于调节零食选择的偏好参数,此处表示受欢迎程度)
* @params sumMoney 总预算
*/
String[] foodName = {"小当家", "牛肉干", "饼干", "香肠", "面包", "麻花", "蛋糕", "麻薯", "桂花饼", "玉米粒", "猪肉干"};
double[] prices = {2.2, 5.8, 1.3, 1.0, 4.7, 1.12, 5.6, 4.5, 6.6, 2.3, 5.4};
double[] lover01 = {4.1, 7.2, 3.3, 5.4, 2.6, 1.1, 6.9, 3.8, 6.7, 4.5, 6.9};
int sumMoney01 = 10;
int sumMoney02 = 30;
int sumMoney03 = 60;
int sumMoney04 = 90;
int sumMoney05 = 140;
  • 效果展示
公司预算:10
实际花费:10.0
选取的零食种类:
小当家*2 玉米粒*1 饼干*1 香肠*2 

公司预算:30
实际花费:29.120000000000005
选取的零食种类:
小当家*1 桂花饼*1 牛肉干*1 猪肉干*1 玉米粒*1 蛋糕*1 饼干*1 香肠*1 麻花*1 

公司预算:60
实际花费:58.319999999999986
选取的零食种类:
小当家*6 桂花饼*7 牛肉干*7 猪肉干*7 玉米粒*7 蛋糕*6 饼干*6 香肠*6 麻花*6 麻薯*1 

公司预算:90
实际花费:88.91999999999999
选取的零食种类:
小当家*11 桂花饼*11 牛肉干*12 猪肉干*12 玉米粒*11 蛋糕*12 面包*1 饼干*11 香肠*11 麻花*11 麻薯*12 

公司预算:140
实际花费:138.4000000000001
选取的零食种类:
小当家*20 桂花饼*20 牛肉干*21 猪肉干*21 玉米粒*20 蛋糕*21 面包*21 饼干*20 香肠*20 麻花*20 麻薯*21 
  • 解题思路

    • 首先是按照 “贪心比=零食喜好度/零食价格” 来对零食重新排序,这个比值说明:零食价格越高越受欢迎,零食价格越低越好,够买的数量越多。
    • 排序采用的是冒泡,考虑到对贪心比、零食价格、零食名 三者进行排序,所以一般考虑冒泡、选择、插入,而尽量不要用快排。
    • 根据贪心比选择食物的时候,设定只选择贪心比靠前的 k 个食品。每个食品的数量是:num = 总价/(X1+X2+X3+X4+…+Xk)。
    • 那么剩余remain_money = 总价 - num*price(X1+X2+X3+X4+…+Xk);
    • 这里我们可以控制的变量分别是:贪心比靠前的 k 个食品、num ,我们可以设置我们想要的k,以及num。
    • 最后将剩余的食品、食品价格、remain_money 做一次动态规划,选择尽可能多的食品出来。
  • 重要代码展示

    • 冒泡排序
//冒泡排序:筛选贪心位置
double[] proportion = new double[length];
for (int i = 0; i < length; i++) {
    proportion[i] = lover[i] / prices[i];
}
boolean flag = false;
for (int i = 0; i < length - 1; i++) {
    for (int j = 0; j < length - 1 - i; j++) {
        if (proportion[j] > proportion[j + 1]) {
            flag = true;
            //贪心比
            double temp = proportion[j];
            proportion[j] = proportion[j + 1];
            proportion[j + 1] = temp;
            //食品名
            String name = foodName[j];
            foodName[j] = foodName[j + 1];
            foodName[j + 1] = name;
            //食品价格
            temp = prices[j];
            prices[j] = prices[j + 1];
            prices[j + 1] = temp;
        }
    }
    if (!flag) {
        break;
    }
    flag = false;
}
  • 贪心装载
while (sumMoney_4temp > prices[point]) {
    sumMoney_temp += prices[point];
    sumMoney_4temp -= prices[point];
    foodList_method3.add(foodName[point]);
    point--;
    //对于特别好吃的,最多只能选5种
    if (length - point >= gap) {
        break;
    }
}
//u:所选产品的倍数,uu:所选产品后,剩余的钱,y:剩余food种类
times = (int) Math.floor(sumMoney / sumMoney_temp);
if (times > 4) {
    times -= 4;
}
double remain_money = sumMoney - times * sumMoney_temp;
  • 动态规划
//逐层规划,外层循环表示背包重量增加
for (int i = 1; i <= sumMoney; i++) {
    //内层循环,遍历物品
    for (int j = 1; j <= prices.length; j++) {

        //如果放入值比背包总重量还大,放弃
        if (prices[j - 1] > i) {
            bestvalue[i][j] = bestvalue[i][j - 1];
        } else {
            bestvalue[i][j] =
                    bestvalue[i][j - 1] > bestvalue[(int) Math.floor(i - prices[j - 1])][j - 1] + prices[j - 1] ?
                            bestvalue[i][j - 1] : (int) (bestvalue[(int) Math.floor(i - prices[j - 1])][j - 1] + prices[j - 1]);
        }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值