Auswahl der kalorienreichsten Mahlzeiten


9

Angenommen, ich esse fünf Mahlzeiten pro Tag, und da es sieben Tage in der Woche gibt, habe ich Rezepte für sieben von jeder Mahlzeit, für insgesamt 35 Rezepte. Jedes Rezept hat eine Kalorienzahl. Jeder Tag muss ein Rezept pro Mahlzeit enthalten, und jedes Rezept ist auf eine bestimmte Mahlzeit festgelegt (z. B. können Sie keine Pfannkuchen zum Abendessen haben). Alle 35 Rezepte müssen in der Lösung enthalten sein, damit ein Rezept während der Woche nicht wiederholt werden kann.

Ich möchte die Anordnung der Mahlzeiten finden, die die gleichmäßigste Kalorienzahl pro Tag ergeben - das heißt, ich möchte den Unterschied in den von Tag zu Tag verbrauchten Gesamtkalorien minimieren.

Dies ist kein Hausaufgabenproblem - es ist tatsächlich wahr! Ich kann mir keinen besseren Ansatz als Brute-Force einfallen lassen, und es gibt 7! ^ 4 Kombinationen, was sehr viel ist.


3
Ich habe das Gefühl, dass dies eine Variation des Schneidmaterialproblems oder vielleicht des Verpackungsproblems ist .
Doval

Zur Verdeutlichung: Sie haben 7 Rezepte für "erste Mahlzeit des Tages", 7 für "zweite Mahlzeit", 7 für "dritte Mahlzeit" und so weiter? Würden Sie jemals ein Rezept für die "erste Mahlzeit" einer "letzten Mahlzeit des Tages" zuweisen? (Anders ausgedrückt, würden Sie Pfannkuchen zum Abendessen servieren?)
Dan Pichelman

Richtig; du würdest nicht.
Dfaulken

2
Haben alle 35 Rezepte signifikant unterschiedliche Kalorienzahlen? Wenn Sie die Kalorienzahl auf die nächsten 10 oder 50 Kalorien runden würden, könnte 7! ^ 4 leicht zu 3! ^ 4 werden - was leicht mit roher Gewalt
berechnet werden kann

2
Alter, du isst zu viel, wenn du 5 Mahlzeiten pro Tag isst, wirst du übergewichtig.
Pieter B

Antworten:


1

So formulieren Sie Ihr Problem formeller:

Sie haben 5 Listen mit jeweils 7 Nummern. Sie müssen 7 Listen mit jeweils 5 Zahlen erstellen und die Lösung finden, die den minimalen Unterschied zwischen der Liste mit der größten Zahlensumme und der Liste mit der kleinsten aufweist.

Wenn Sie die optimale Lösung ohne Heuristik finden möchten, haben Sie meiner Meinung nach keine andere Wahl, als aufzuzählen, aber Sie müssen nicht alle aufzählen.

Welche Lösung Sie auch finden, wenn Sie sie als "bisher am besten gefunden" registrieren, registrieren Sie ihre Leistung in Bezug auf Ihre Metrik (ich glaube, es ist ein Min-Max-Unterschied). Wenn ein Lösungszweig davon eindeutig abseits liegt, hören Sie auf, ihn aufzuzählen. Protip: Nicht gebaute Tage haben bestenfalls eine Kalorienzahl, die der Durchschnitt aller verbleibenden Mahlzeiten ist. Stellen Sie sich also vor, Sie haben Listen, die [10, 2, 2, 1, 1, 0, 0]für alle 5 Mahlzeiten gelten, und Sie haben die Lösung 10 für jede Mahlzeit für Tag 1 erstellt. Sie wissen, dass die verbleibenden Tage durchschnittlich 5 Kalorien pro Tag betragen, sodass der Unterschied mindestens 45 beträgt Sie haben zuvor eine Lösung gefunden, zum Beispiel max - min = 10, dass Sie nicht weiter gehen müssen. Sie werden direkt ein anderes Menü für Tag 1 ausprobieren.


Es ist kein Papierkorbproblem. Ein Behälterproblem ist nicht die feste Anzahl von Behältern und nicht die feste Anzahl von Artikeln pro Behälter.
Paparazzo

Ja, du hast recht. Ich werde das korrigieren.
Arthur Havlicek

0

Dies ist nur ein Hack, aber es bringt Sie in die Nähe.
Nur 3 Mahlzeiten
Sie floppen im Grunde genommen Mahlzeiten, wenn sich die zwei Tage dem durchschnittlichen C # nähern

Ein besserer Ansatz wäre, einen Boolen auf Flop zurückzugeben und bis zum Abschluss zu iterieren.

Flop könnte schlauer werden. Möglicherweise sind Sie in der Lage, das Frühstück nicht zu floppen, um das Mittag- und Abendessen zu floppen. Es gibt möglicherweise harte Code-Permutationen. Dies ist eher eine Sortierung, bei der Flop-Werte eher als Sortierung verwendet werden.

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
Gibt es eine Möglichkeit, dem Code eine Erklärung oder einige Kommentare hinzuzufügen, damit die Antwort hilfreicher / aufschlussreicher wird? Ich glaube, ich verstehe, was da drin los ist, aber ich kann nicht sicher sein.
Adam Wells

@ AdamWells Ich habe ein paar Kommentare hinzugefügt. Was verstehst Du nicht?
Paparazzo

Es hat einfach nicht mit Flop geklickt. Macht jetzt Sinn, danke!
Adam Wells

Ich kann nicht einmal sagen, ob dies Java-Code ist. Ist es ? Entschuldigung, meine Java- und Cx-Tage liegen weit hinter mir. Wo ist die Hauptleitung überhaupt?
Arthur Havlicek

@ArthurHavlicek Der Code C #. Sie sehen sehr ähnlich aus.
Paparazzo

0

Berechnen Sie zuerst die durchschnittliche Kalorienzahl pro Mahlzeit. Berechnen Sie dann die durchschnittliche Anzahl der Farben pro Tag. Dies sind die Metriken, an denen man messen kann. Als nächstes sortieren Sie die Mahlzeiten.

Wählen Sie jetzt einfach die höchsten und niedrigsten Mahlzeiten aus der Sorte aus. Wenn sich eine Mahlzeit im selben Zeitfenster befindet, müssen Sie zum nächstniedrigeren oder höchsten Punkt wechseln, bis Sie eine Mahlzeit finden, die sich nicht in diesem Zeitfenster befindet (Abendessen usw.). Tun Sie dies für die ersten 4 Mahlzeiten (hi / low). Wählen Sie bei der 5. Mahlzeit eine Mahlzeit aus, die dem Durchschnitt am nächsten kommt. Speichern Sie die 5. Mahlzeit in einem separaten Eimer. Spülen und 7 Mal wiederholen.

Dies ist Ihre erste Mahlzeit. Das wird ziemlich gleichmäßig sein. Wenn Sie die optimale Verteilung wünschen, können Sie mit der 5. Mahlzeit eine weitere Verfeinerung vornehmen.

Gehen Sie durch den Eimer mit der 5. Mahlzeit und versuchen Sie, die 5. Mahlzeit zwischen den Tagen auszutauschen, um festzustellen, ob die Mahlzeiten noch weiter ausgeglichen sind. Sie müssen immer noch dieselben Regeln anwenden (nicht mehr als eine Mahlzeit pro Zeit). Man kann oder kann nicht einen gleichmäßigeren Satz bekommen. Verwenden Sie die berechneten Durchschnittswerte früher, um festzustellen, ob eine Verbesserung vorliegt oder nicht. Es wird viel weniger Kombinationen geben, da die ersten 4 Mahlzeiten basierend auf Hoch / Niedrig festgelegt werden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.