求优化排列组合算法(付红包)

需求:

我手里有个菜品库,分类有主食、肉类、汤类、蔬菜类。
每个菜有各自的每1克的能量、碳水化合物、脂肪、蛋白质含量。

要求:

1、早餐对这4个分类的菜进行组合,每个分类的菜只能选择一个
2、选取4个分类的菜后,进行能量、碳水化合物、脂肪、蛋白质含量的分配
3、要求4个菜的能量、碳水化合物、脂肪、蛋白质含量各自的和相加,不超过各自的最小值和最大值。

这里注意,最小和最大的增长有一个步长。比如鸡蛋,不可能只吃1g。min(5)~max(20),step可能是5。5、10、15、20这样,食物要有完整性

我的方案:

1、写一个while循环
2、rand随机根据分类取一条菜品,将4个菜先放到数组里
3、然后循环这4个菜品,在随机给他们分配克重
4、对4个菜品进行能量、碳水化合物、脂肪、蛋白质含量的累加,然后对比各自的最小值和最大值。
5、如果4个菜的能量、碳脂蛋在范围内,则结束while循环。

缺点:

1、循环次数过大,需要无限次的匹配才能找到
2、菜品库的数据量不够多的时候,很有可能匹配不出来

希望:

有没有大哥有其他什么方案的,能够快速找到:
1、优化算法,或者借助其他什么工具、组建
2、能不能提前知道库中的的所有菜品的组合是否可以配出合适的菜品

奖励

如果有最佳答案,我会附上200元红包。

提供方案要求

1、写出文字步骤
2、更详细的代码可以飞书文档或者learnku写一个博文@我
3、数据可以自行模拟

示例数据

求优化排列组合算法(有红包奖励)

《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 35

问一下GPT吧,他最擅长这种算法

2周前 评论
博学多才的走停 (楼主) 2周前

在循环次数和查询时间取一个最优解。例如将循环100次中的最优解返回,可以根据具体需求优化算法,比如减肥餐肯定要求碳水低,但又不能影响健康的前提下进行搭配。

2周前 评论

有 在随机给他们分配克重 就没法很好的用算法了!

可以每个类按次随机,最后一个数据判断结果在不在范围内,在范围内就随机,不在就从头开始

2周前 评论
博学多才的走停 (楼主) 2周前
deatil (作者) 2周前
博学多才的走停 (楼主) 2周前
博学多才的走停 (楼主) 2周前
deatil (作者) 2周前
deatil (作者) 2周前
博学多才的走停 (楼主) 2周前
deatil (作者) 2周前

先不说“能量、碳水化合物、脂肪、蛋白质含量各自的和相加,不超过各自的最小值和最大值”这个要求,假定每种菜品重量上限100克,就有C(4,4) * 100^4上百万种可能,这样一次性返回结果先不说耗时情况,内存怕都不够。有没有种可能直接改需求呢?像省市县三级联动一样来个四级联动,让用户分别选择菜品,重量,最后计算能量、碳水总和看是否在合适范围内?

2周前 评论
博学多才的走停 (楼主) 2周前
博学多才的走停 (楼主) 2周前
kis龍 2周前
博学多才的走停 (楼主) 2周前
kis龍 2周前
zzzzzq (作者) 2周前
kis龍 2周前
博学多才的走停 (楼主) 2周前
porygonCN

看看动态规划算法吧

2周前 评论
博学多才的走停 (楼主) 2周前

猴子排序 :joy:全看用户个人运气

2周前 评论
sanders

有意思,感觉像变形的旅行商问题,蹲个方案。

2周前 评论

有意思,蹲个方案。

2周前 评论

复杂的问题简单化 直接将所有的排和组合,以及总分数,直接存储 使用的时候直接搜索就好了,存储上如果mysql支持不了,可以使用es等

2周前 评论
zion_xayts_com (作者) 2周前
博学多才的走停 (楼主) 2周前

给出的示例数据就有问题了,能量虽然给出的是每种菜品100g的量,但后续还列出了菜品最少搭配的克数要求,由当前给出的示例量来说,不管如何都已经无法满足能量不超300的要求,而且就目前的匹配规则来看,如果需求是必须尽可能的匹配到满足条件组合菜品的话,那这个匹配量很大,四个属性外加重量限制,一个不满足等于全部又要重新组合,但重新组合之后,原先的数据又是可以复用不能排除;感觉这种计算程度是不是安排成后台设定选择固定的菜品绑定(可多种菜品组合),然后计算不能的菜品组合来计算菜的占重,而不是使用全随机的方式进行菜品组合的计算

2周前 评论
博学多才的走停 (楼主) 2周前

试了一下把全部步长生成出来之后,单独匹配四列的组合,最后再根据下标取一个成功匹配的组合,在少量的菜品数和步长数的情况下还能计算,但只要其中一种数量太大就直接爆炸,不过生成的数据不是线性增长的,线性增长数据的提前退出增多可能会快一点吧,同种情况下,JAVA好像会快点 $caiOne = [[[“id”=>1,”name”=>”名称”,”one”=>1,”two”=>1,”three”=>1,”four”=>1]]]

/**
     * 计算单列组合
     * @param string $str 单列
     * @param array $caiOne 一类菜品数据
     * @param array $caiTwo 二类菜品数据
     * @param array $caiThree 三类菜品数据
     * @param array $caiFour 四类菜品数据
     * @return array
     */
    public static function mathArrStart($str,$caiOne,$caiTwo,$caiThree,$caiFour)
    {
        /**
         * 循环同一列获取满足条件的所有菜系组合
         */
        $end = [];
        //顶层循环取菜品数最少列,可以减少循环时间  //todo
        foreach ($caiOne as $caiOneKey => $val){
            foreach ($val as $caiOneValKey => $itemOne){
                $minOne = 100 - $itemOne[$str];
                $maxOne = 300 - $itemOne[$str];
                //大于最大重量直接退出
                if ($maxOne <= 0){
                    continue;
                }
                foreach ($caiTwo as $caiTwoKey => $valTwo){
                    foreach ($valTwo as $caiTwoValKey=> $itemTwo){
                        $minTwo = $minOne - $itemTwo[$str];
                        $maxTwo = $maxOne - $itemTwo[$str];
                        //大于最大重量直接退出
                        if ($maxTwo <= 0){
                            continue;
                        }
                        foreach ($caiThree as $caiThreeKey=> $valThree){
                            foreach ($valThree as $caiThreeValKey=> $itemThree){
                                $minThree = $minTwo - $itemThree[$str];
                                $maxThree = $maxTwo - $itemThree[$str];
                                //大于最大重量直接退出
                                if ($maxThree <= 0){
                                    continue;
                                }
                                foreach ($caiFour as $caiFourKey => $valFour){
                                    foreach ($valFour as $caiFourValKey => $itemFour){
                                        //最小重量不满足,直接退出
                                        $minFour = $minThree - $itemFour[$str];
                                        if ($minFour > 0){
                                            continue;
                                        }
                                        //大于最大重量直接退出
                                        $maxFour = $maxThree - $itemFour[$str];
                                        if ($maxFour < 0){
                                            continue;
                                        }
                                        //只保留一种相同菜系组合
                                        $idx = $itemOne["id"].",".$itemTwo["id"].",".$itemThree["id"].",".$itemFour["id"];
                                        if (!isset($end[$idx])){
                                            $end[$itemOne["id"].",".$itemTwo["id"].",".$itemThree["id"].",".$itemFour["id"]] = [
                                                $minFour,$maxFour,
                                                $itemOne["name"],
                                                $itemTwo["name"],
                                                $itemThree["name"],
                                                $itemFour["name"],
                                            ];
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return $end;
    }

2周前 评论
博学多才的走停 (楼主) 2周前
小猪蹄子 (作者) 1周前
HACK_QC

这个不是很典型的递归回溯算法,直接使用递归回溯的模版就可以写出来了

2周前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!