Підбір найбільш калорійної організації страв


9

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

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

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


3
У мене в кишках відчувається, що це є варіантом проблеми запасу різання або, можливо, проблема з упаковкою у відро .
Doval

Для уточнення - у вас є 7 рецептів «першого прийому їжі дня», 7 для «2-ї їжі», 7 для «3-ї їжі» тощо? Ви коли-небудь призначили рецепт "першої страви" "останній прийом їжі дня"? (По-іншому, ви б
подавали

Правильно; ти б не зробив.
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 при кожному прийомі їжі протягом 1 дня. Ви знаєте, що в інші дні буде в середньому 5 калорій на день, тож різниця становитиме щонайменше 45 і так, якщо Ви раніше знайшли рішення, скажімо max - min = 10, далі вам не доведеться йти. Ви безпосередньо спробуєте інше меню на перший день.


Це не проблема сміття. Проблема сміття не є фіксованою кількістю контейнерів і не фіксованою кількістю елементів на кошик.
папараццо

Так, ти правий. Я правильно виправлю це.
Артур Гавлічек

0

Це просто злом, але ви зблизите
лише 3 прийоми їжі.
Ви, в основному, їжі, якщо це зробить два дні ближче до середнього C #

Кращим підходом було б повернення булену на Flop та ітерацію до завершення.

Флоп може стати розумнішим. Можливо, ви не можете снідати сніданок, щоб поласувати обідом та вечерею. Можливо, жорсткі перестановки коду. Це більше схоже на сортування, де 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

Спочатку обчисліть середню кількість калорій за прийом їжі. Потім обчисліть середнє число кольорів на день. Це будуть показники, проти яких можна виміряти. Далі сортуйте страви.

Тепер просто вибирайте найвищі та найнижчі страви із сорту. Якщо їжа знаходиться в одному і тому ж місці, то вам доведеться перейти до наступного найнижчого або найвищого, поки ви не знайдете їжу, яка не знаходиться в цьому часовому слоті (вечеря тощо). Робіть це для перших 4 прийомів їжі (привіт / низький). На 5-му прийомі їжі виберіть страву, яка вам найближча до середнього. Збережіть 5-ту страву в окремому відрі. Промийте і повторіть 7 разів.

Це буде ваш початковий набір їжі. Це буде досить рівно. Якщо ви хочете оптимального розподілу, можна додатково вдосконалити 5-ту їжу.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.