选择热量最多的食物


9

假设我每天吃五顿饭,并且由于一周中有七天,我每顿饭有七个食谱,总共35个食谱。每个食谱都有卡路里计数。每一餐每一天都必须包含一个食谱,并且每个食谱都固定于特定的一餐(例如晚餐不能吃煎饼)。解决方案中必须包含所有35种食谱,因此一周内不能重复食谱。

我想找到可以每天提供最多卡路里数的膳食安排-也就是说,我想使每天消耗的总卡路里之间的差异最小化。

这不是作业问题,这是事实!我无法提供比暴力破解更好的方法,并且有7!^ 4个组合,这很多。


3
我有种直觉,认为这是切削料问题或料箱包装问题的一种变体。
2013年

需要说明的是-您有7个“当天第一餐”食谱,7个“第二餐”食谱,7个“第三餐”食谱,依此类推?您是否将“第一餐”食谱分配给“一天的最后一餐”?(换一种方式,您晚餐吃煎饼吗?)
丹·皮切尔曼

正确; 你不会。
dfaulken '16

2
所有35种食谱的卡路里计数都明显不同吗?如果将卡路里数四舍五入到最接近的10或50卡,则7!^ 4可能很容易变成3!^ 4-通过蛮力可以轻松计算
Dan Pichelman

2
杜德,你吃得太多了,每天吃5顿饭会使你超重。
Pieter B

Answers:


1

要对问题采取更正式的方法:

您有5个包含7个数字的列表。您需要构建7个列表,每个列表包含5个数字,然后找到在最大数字和最小数字之间的差异最小的解决方案。

如果您想找到没有启发式的最佳解决方案,我相信您除了枚举外别无选择,但您不必全部列举。

无论找到什么解决方案,当您将其注册为“迄今为止最好的”时,请针对您的指标注册其性能(我相信这是最小-最大差异)。然后,如果解决方案分支显然不在此范围之内,请停止枚举。提示:非住宿日的卡路里计数最多为所有剩余膳食的平均值。因此,想象一下,您拥有[10, 2, 2, 1, 1, 0, 0]所有5餐的清单,并且在第1天的每餐中构建了10个解决方案。您知道剩余的天平均每天5卡路里,因此差异至少为45,所以如果您以前找到了的解决方案,例如max - min = 10,您无需再进行任何操作。您将在第一天直接尝试其他菜单。


这不是垃圾箱问题。垃圾箱问题不是固定数目的垃圾箱,也不是每个垃圾箱中的项目数固定。
狗仔队

是的,你是对的。会改正的。
亚瑟·哈夫利切克

0

这只是一个hack,但可以使您关闭
仅三餐
你基本上翻牌的饭菜,如果它使这两天更接近平均C#

更好的方法是在Flop上返回一个布尔值,然后迭代直到完成。

翻牌会变得更聪明。您可能不会在早餐和晚餐前放过早餐。可能存在硬代码排列。这更像是翻牌值而不是排序的排序。

public static void MealEven()
{
    List<Day> Days = new List<Day>();
    Random rnd = new Random();
    decimal sum = 0;
    for(int i = 0; i<7; i ++)
    {
        int b = rnd.Next(100) + 40;
        int l = rnd.Next(100) + 60;
        int d = rnd.Next(100) + 80;
        Meal br = new Meal(enumMeal.b, b);
        Meal lu = new Meal(enumMeal.l, l);
        Meal di = new Meal(enumMeal.d, d);
        Day day = new Day(br, lu, di);
        Days.Add(day);
        sum += day.Calories;
    }
    decimal avg = sum / 7;
    foreach (Day d in Days.OrderBy(x => x.Calories))
        System.Diagnostics.Debug.WriteLine(d.Calories);
    System.Diagnostics.Debug.WriteLine("");

    Day low;
    Day high;
    Day lowLast = null;
    Day highLast = null;
    int count = 0;
    while (true)
    {   // first do high and low
        low = Days.OrderBy(x => x.Calories).FirstOrDefault();
        high = Days.OrderByDescending(x => x.Calories).FirstOrDefault();
        if (lowLast != null && lowLast == low && highLast == high)
            break;
        if (count > 1000)
            break;
        lowLast = low;
        highLast = high;
        count++;               
        Flop(ref high, ref low);
    }
    foreach (Day d in Days.OrderBy(x => x.Calories))
        System.Diagnostics.Debug.WriteLine("{0} {1} {2} {3}", d.Calories, d.B.Calories, d.L.Calories, d.D.Calories);
    System.Diagnostics.Debug.WriteLine("");

    // day a one on one pass
    for (int i = 0; i < 7; i ++)
    {
        for (int j = 0; j < 7; j++)
        {
            if (i == j)
                continue;
            Day d1 = Days[i];
            Day d2 = Days[j];
            Flop(ref d1, ref d2);
        }
    }

    foreach (Day d in Days.OrderBy(x => x.Calories))
        System.Diagnostics.Debug.WriteLine("{0} {1} {2} {3}", d.Calories, d.B.Calories, d.L.Calories, d.D.Calories);
    System.Diagnostics.Debug.WriteLine("");
}
public static void Flop (ref Day high, ref Day low)
{
    if(low.Calories > high.Calories)
    {
        int hold = low.B.Calories;
        low.B.Calories = high.B.Calories;
        high.B.Calories = hold;

        hold = low.L.Calories;
        low.L.Calories = high.L.Calories;
        high.L.Calories = hold;

        hold = low.D.Calories;
        low.D.Calories = high.D.Calories;
        high.D.Calories = hold;

    }
    decimal avg = (low.Calories + high.Calories) / (decimal)2;
    int bDiff = (high.B.Calories - low.B.Calories) < 0 ? 0 : (high.B.Calories - low.B.Calories);
    int lDiff = high.L.Calories - low.L.Calories < 0 ? 0 : (high.L.Calories - low.L.Calories);
    int dDiff = high.D.Calories - low.D.Calories < 0 ? 0 : (high.D.Calories - low.D.Calories);
    // only flop is one does not go past the average  
    if (bDiff > 0 && ((low.Calories + bDiff) < avg || (high.Calories - bDiff) > avg))
    {
        int hold = low.B.Calories;
        low.B.Calories = high.B.Calories;
        high.B.Calories = hold;
    }
    if (lDiff > 0 && ((low.Calories + lDiff) < avg || (high.Calories - lDiff) > avg))
    {
        int hold = low.L.Calories;
        low.L.Calories = high.L.Calories;
        high.L.Calories = hold;
    }
    if (dDiff > 0 && ((low.Calories + dDiff) < avg || (high.Calories - dDiff) > avg))
    {
        int hold = low.D.Calories;
        low.D.Calories = high.D.Calories;
        high.D.Calories = hold;
    }
}
public enum enumMeal {b, l, d};
public class Day
{
    public Meal B { get; set; }
    public Meal L { get; set; }
    public Meal D { get; set; }
    public Decimal Calories { get { return (Decimal)(B.Calories + L.Calories + D.Calories); } }
    public Day (Meal b, Meal l, Meal d )
    {
        B = b;
        L = l;
        D = d;
    }
}
public class Meal
{
    public enumMeal Type { get; set; }
    public int  Calories { get; set; }
    public Meal (enumMeal meal, int calories)
    {
        Type = meal;
        Calories = calories;
    }
}   

1
有什么办法可以在代码中添加解释或注释,以使答案更有帮助/更有启发性?我想我知道那里发生了什么,但我不确定。
亚当·威尔斯

@AdamWells我添加了一些评论。你有什么不明白?
狗仔队

它只是没有在翻牌圈跟注。现在有意义,谢谢!
亚当·威尔斯

我什至不知道这是否是Java代码。是吗 ?抱歉,我的Java和Cx时代已经远远落后于我。反正主要在哪里?
亚瑟·哈维利切克

@ArthurHavlicek代码C#。他们看起来很一样。
狗仔队

0

首先计算每餐的平均卡路里数。然后计算每天的平均色料数。这些将是可以衡量的指标。接下来整理饭菜。

现在,只选择最高和最低的饭菜。如果在同一时段进餐,则您必须转到下一个最低或最高的时段,直到找到不在该时段内的餐点(晚餐等)。前四餐(高/低)进行此操作。在第五餐时,选择一餐能使您最接近平均水平的餐点。将第五餐保存到单独的桶中。冲洗并重复7次。

这将是您最初的饭菜。这甚至会很漂亮。如果您想要最佳的分配,可以在第5餐时做一些进一步的细化。

通过第五餐桶,尝试在两天之间交换五餐,以查看餐点是否均匀。您仍然必须应用相同的规则(每次不超过一顿饭)。一个人可能会或可能不会得到更均匀的设置。尽早使用计算出的平均值来查看是否有改善。因为前4餐是根据高/低固定的,所以组合会少很多。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.