Scegliere la disposizione dei pasti più calorica


9

Supponiamo di mangiare cinque pasti al giorno e, dato che ci sono sette giorni alla 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 è fissata a un pasto particolare (ad es. Non è possibile avere frittelle 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 conteggio delle calorie più uniforme al giorno, cioè voglio minimizzare la differenza nelle calorie totali consumate di giorno in giorno.

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


3
Ho la sensazione che si tratti di una variazione del problema del materiale di taglio o forse del problema dell'imballaggio del contenitore .
Doval,

Per chiarire: hai 7 ricette per il "primo pasto del giorno", 7 per il "2 ° pasto", 7 per il "3 ° pasto" e così via? Assegneresti mai una ricetta del "primo pasto" a un "ultimo pasto della giornata"? (In altre
parole, serviresti le

Corretta; non vorrai.
dfaulken,

2
Tutte e 35 le ricette hanno conteggi calorici significativamente diversi ? Se dovessi arrotondare il conteggio delle calorie alle 10 o 50 calorie più vicine, 7! ^ 4 potrebbe facilmente diventare 3! ^ 4 - che è facilmente calcolabile tramite la forza bruta
Dan Pichelman,

2
Amico, mangi troppo, mangiare 5 pasti al giorno ti farà perdere peso.
Pieter B,

Risposte:


1

Per fare un approccio più formale al tuo problema:

Hai 5 elenchi di 7 numeri ciascuno. È necessario creare 7 elenchi di 5 numeri ciascuno e trovare la soluzione che presenta la minima differenza tra l'elenco che ha la più grande somma di numeri e quello con il più piccolo.

Se vuoi trovare la soluzione ottimale senza euristica, credo che tu abbia poca scelta se non quella di elencare, ma non devi elencarle tutte.

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


Non è un problema bin. Un problema del cestino non è il numero fisso di contenitori e non il numero fisso di articoli per contenitore.
paparazzo,

Si hai ragione. Mal che corretto.
Arthur Havlicek,

0

Questo è solo un trucco ma ti farà chiudere
Solo 3 pasti
Fondamentalmente flop i pasti se avvicina i due giorni al C # medio

Un approccio migliore sarebbe quello di restituire un valore boolen al flop e iterare fino al completamento.

Il flop potrebbe diventare più intelligente. Potresti essere in grado di non flop fare colazione per flop a pranzo e cena. Ci sono forse permutazioni del codice reale. Questo è più simile a un ordinamento in cui i valori del flop piuttosto che l'ordinamento.

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
esiste un modo per aggiungere una spiegazione o alcuni commenti al codice per ottenere una risposta più utile / illuminante? Penso di capire cosa sta succedendo lì dentro ma non posso esserne sicuro.
Adam Wells,

@AdamWells Ho aggiunto un paio di commenti. Cosa non capisci?
paparazzo,

Semplicemente non ha fatto clic con il flop. Ha senso ora, grazie!
Adam Wells,

Non so nemmeno se questo è il codice Java. È ? Mi dispiace, i miei giorni Java e Cx sono molto indietro. Dov'è comunque il principale?
Arthur Havlicek,

@ArthurHavlicek Il codice C #. Sembrano molto simili.
paparazzo,

0

Calcola innanzitutto il conteggio calorico medio per pasto. Quindi calcola il conteggio medio dei coloranti al giorno. Queste saranno le metriche su cui si può misurare. Quindi ordinare i pasti.

Ora scegli i pasti più alti e più bassi del genere. Se un pasto si trova nella stessa fascia oraria, dovrai andare al successivo più basso o più alto fino a trovare un pasto che non si trova in quella fascia oraria (cena, ecc.). Fallo per i primi 4 pasti (alta / bassa). Al quinto pasto, scegli un pasto che ti avvicini alla media. Salva il 5 ° pasto in un secchio separato. Risciacquare e ripetere 7 volte.

Questo sarà il tuo set iniziale di pasti. Questo sarà abbastanza uniforme. Se si desidera una distribuzione ottimale, è possibile effettuare un ulteriore affinamento con il 5 ° pasto.

Passare attraverso il secchio del 5 ° pasto e provare a scambiare i pasti 5 ° pasto tra i giorni per vedere se i pasti si estendono ancora di più. Dovrai comunque applicare le stesse regole (non più di un pasto alla volta). Si può o meno ottenere un set più uniforme. Utilizzare le medie calcolate in precedenza per vedere se c'è un miglioramento o meno. Ci saranno molte meno combinazioni poiché i primi 4 pasti sono fissi in base al massimo / minimo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.