Выбор наиболее калорийной расстановки блюд


9

Предположим, я ем пять раз в день, а поскольку в неделю семь дней, у меня есть рецепты по семь на каждый прием пищи, всего 35 рецептов. Каждый рецепт имеет количество калорий. Каждый день должен содержать один рецепт на каждый прием пищи, и каждый рецепт привязан к определенному приему пищи (например, на ужин не должно быть блинов). Все 35 рецептов должны быть в растворе, поэтому рецепт не может повторяться в течение недели.

Я хочу найти схему питания, которая обеспечит максимально равномерное количество калорий в день, то есть я хочу минимизировать разницу в общем количестве потребляемых калорий изо дня в день.

Это не домашнее задание - это правда! Я не могу придумать лучший подход, чем грубая сила, и есть 7! ^ 4 комбинаций, что много.


3
У меня есть ощущение, что это вариация проблемы режущего материала или, может быть, проблема упаковки бункера .
Доваль

Чтобы уточнить - у вас есть 7 рецептов для «первого приема пищи», 7 для «второго приема пищи», 7 для «третьего приема пищи» и так далее? Вы когда-нибудь назначали рецепт "первого приема пищи" на "последний прием пищи в день"? (Другими словами, вы бы
подали

Правильный; ты не станешь.
dfaulken

2
У всех 35 рецептов есть существенно различное количество калорий? Если бы вы округлили количество калорий до ближайших 10 или 50 калорий, 7! ^ 4 могло бы легко стать 3! ^ 4 - что легко вычислить с помощью грубой силы
Дан Пичелман

2
Чувак, ты ешь слишком много, едят 5 раз в день, и у тебя будет лишний вес.
Питер Б

Ответы:


1

Чтобы сделать более формальный подход к вашей проблеме:

У вас есть 5 списков по 7 номеров в каждом. Вам нужно построить 7 списков по 5 номеров в каждом и найти решение, которое имеет минимальную разницу между списком, имеющим наибольшую сумму чисел, и списком с наименьшим.

Если вы хотите найти оптимальное решение без эвристики, я считаю, что у вас нет другого выбора, кроме как перечислять, но вам не нужно перечислять все из них.

Какое бы решение вы ни нашли, когда вы зарегистрируете его как «лучшее из найденных», зарегистрируйте его эффективность в отношении вашей метрики (я полагаю, это минимально-максимальная разница). Затем, если ветвь решения явно находится в стороне от этого, прекратите перечислять его. Подсказка: в неурожайные дни в лучшем случае будет учитываться количество калорий, которое является средним для всех оставшихся блюд. Итак, представьте, что у вас есть списки, предназначенные [10, 2, 2, 1, 1, 0, 0]для всех 5 приемов пищи, и вы создали решение 10 при каждом приеме пищи в первый день. Вы знаете, что оставшиеся дни будут составлять в среднем 5 калорий в день, поэтому разница будет составлять не менее 45, и если ранее вы нашли решение, скажем max - min = 10, вам не нужно идти дальше. Вы непосредственно попробуете другое меню для первого дня.


Это не проблема мусорного ведра. Проблема с корзиной заключается не в фиксированном количестве корзин и не в фиксированном количестве элементов в корзине.
Папараццо

Да ты прав. Я исправлю это.
Артур Гавличек

0

Это всего лишь взлом, но это поможет вам закрыть
только 3 приема пищи.
Вы в основном отказываетесь от еды, если это приближает два дня к среднему значению C #

Лучшим подходом было бы вернуть boolen на флопе и повторять до завершения.

Флоп может стать умнее. Вы можете быть в состоянии не проваливать завтрак, чтобы проваливать обед и ужин. Там может быть жесткий перестановки кода. Это больше похоже на сортировку, где значения флопа, а не сортировки.

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

Сначала вычислите среднее количество калорий за прием пищи. Затем вычислите среднее количество цветов в день. Это будут показатели, которые можно измерить. Далее сортируй блюда.

Теперь просто выберите самую высокую и самую низкую еду из этого вида. Если еда находится в одном и том же временном интервале, вам придется переходить к следующему наименьшему или максимальному значению, пока вы не найдете блюдо, которого нет в этом временном интервале (ужин и т. Д.). Сделайте это для первых 4-х блюд (привет / низ). На 5-й еде выберите еду, которая приближает вас к среднему. Сэкономьте 5 еду в отдельном ведре. Промыть и повторить 7 раз.

Это будет ваш начальный набор блюд. Это будет довольно даже. Если вы хотите оптимальное распределение, то с 5-ым приемом пищи можно провести дополнительную обработку.

Пройдите через ведро с 5-ым приемом пищи и попробуйте поменять местами 5-й прием пищи между днями, чтобы увидеть, выровняется ли прием пищи еще дальше. Вам все равно придется применять те же правила (не более одного приема пищи за раз). Можно или не может получить более равномерный набор. Используйте вычисленные средние значения ранее, чтобы увидеть, есть ли улучшение или нет. Комбинаций будет намного меньше, поскольку первые 4 приема пищи фиксируются на основе высоких / низких значений.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.