Scegliere l'arrangiamento più calorico dei pasti

9

Supponiamo di mangiare cinque pasti al giorno, e poiché ci sono sette giorni in una settimana, ho ricette per sette di ogni pasto, per 35 ricette in totale. Ogni ricetta ha un conteggio delle calorie. Ogni giorno deve contenere una ricetta per pasto e ogni ricetta è fissa per un pasto particolare (ad esempio non è possibile avere pancake per cena). Tutte le 35 ricette devono essere nella soluzione, quindi una ricetta non può essere ripetuta durante la settimana.

Voglio trovare la disposizione dei pasti che fornirà il massimo numero di calorie al giorno, ovvero, voglio ridurre al minimo la differenza delle calorie totali consumate di giorno in giorno.

Questo non è un problema di compiti a casa - è vero! Non riesco a trovare un approccio migliore della forza bruta, e ci sono 7! ^ 4 combinazioni, che è molto.

    
posta dfaulken 18.10.2016 - 17:46
fonte

3 risposte

1

Per dare un approccio più formale al tuo problema:

Hai 5 liste di 7 numeri ciascuna. Devi creare 7 liste di 5 numeri ciascuna e trovare la soluzione che presenta la differenza minima tra la lista che ha la più grande somma di numeri e quella con la più piccola.

Se vuoi trovare la soluzione ottimale senza euristica, credo che tu abbia poca scelta, ma per enumerare, ma non devi enumerarli tutti.

Qualunque sia la soluzione che trovi, quando la registri come "la migliore trovata finora", registra le sue prestazioni riguardo alla tua metrica (credo che sia la differenza min-max). Quindi, se un ramo di soluzione è chiaramente fuori strada, smetti di enumerarlo. Protip: i giorni non costruiti avranno nel migliore dei casi un conteggio delle calorie che è la media di tutti i pasti rimanenti. Quindi, immagina di avere liste che sono [10, 2, 2, 1, 1, 0, 0] per tutti e 5 i pasti, e hai costruito la soluzione 10 ad ogni pasto per il giorno 1. Sai che i giorni restanti saranno in media 5 calorie al giorno, quindi la differenza sarà almeno 45 e quindi se hai trovato in precedenza una soluzione di, diciamo, max - min = 10 , non devi andare oltre. Proverai direttamente un altro menu per il giorno 1.

    
risposta data 18.10.2016 - 21:12
fonte
0

Questo è solo un trucco ma ti farà avvicinare a Solo 3 pasti
In pratica flop i pasti se rende i due giorni più vicini alla media C #

Un approccio migliore sarebbe quello di restituire un boolen su Flop e iterare fino al completamento.

Flop potrebbe diventare più intelligente. Potresti trovarti nella posizione di non far floppare la colazione per floppare il pranzo e la cena. Ci sono forse permutazioni hardcode. Questo è più simile a un tipo in cui i valori di flop piuttosto che sort.

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;
    }
}   
    
risposta data 18.10.2016 - 20:54
fonte
0

Calcola innanzitutto il conteggio delle calorie medie per pasto. Quindi calcola il conteggio delle colorie medio al giorno. Queste saranno le metriche su cui è possibile misurare. Quindi ordina i pasti.

Ora scegli solo i pasti più alti e quelli più bassi. Se un pasto si trova nella stessa fascia oraria, dovrai andare al livello più basso o più alto finché non trovi un pasto che non si trova in quella fascia oraria (cena, ecc.). Fatelo per i primi 4 pasti (ciao / basso). Al quinto pasto scegli un pasto che ti avvicini di più alla media. Salva il quinto pasto in un secchio separato. Risciacquare e ripetere 7 volte.

Questa sarà la tua prima serie di pasti. Questo sarà abbastanza uniforme. Se si desidera la distribuzione ottimale, è possibile eseguire ulteriori rifiniture con il 5 ° pasto.

Attraversa il secchio del quinto pasto e prova a scambiare i pasti 5 giorni tra un giorno e l'altro per vedere se i pasti sono ancora più lunghi. Dovrai comunque applicare le stesse regole (non più di un pasto alla volta). Si può o non si può ottenere un set più uniforme. Usa le medie calcolate prima per vedere se c'è un miglioramento o no. Ci saranno molte meno combinazioni dato che i primi 4 pasti sono fissi in base al livello alto / basso.

    
risposta data 19.10.2016 - 18:19
fonte

Leggi altre domande sui tag