Choisir l'arrangement le plus calorique des repas


9

Supposons que je mange cinq repas par jour, et comme il y a sept jours par semaine, j'ai des recettes pour sept de chaque repas, pour 35 recettes au total. Chaque recette a un nombre de calories. Chaque jour doit contenir une recette par repas, et chaque recette est fixée à un repas particulier (par exemple, vous ne pouvez pas avoir de crêpes pour le dîner). Les 35 recettes doivent être dans la solution, donc une recette ne peut pas être répétée pendant la semaine.

Je veux trouver la disposition des repas qui donnera le plus de calories par jour - c'est-à-dire que je veux minimiser la différence de calories totales consommées au jour le jour.

Ce n'est pas un problème de devoirs - c'est en fait vrai! Je ne peux pas proposer une meilleure approche que la force brute, et il y a 7! ^ 4 combinaisons, ce qui est beaucoup.


3
J'ai l'intuition que c'est une variation du problème du stock de coupe ou peut-être du problème d'emballage du bac .
Doval

Pour clarifier - vous avez 7 recettes pour "premier repas de la journée", 7 pour "2ème repas", 7 pour "3ème repas", et ainsi de suite? Souhaitez-vous jamais attribuer une recette de "premier repas" à un "dernier repas de la journée"? (Autrement dit, seriez-vous
prêt à

Correct; Vous ne voudriez pas.
dfaulken

2
Les 35 recettes ont-elles toutes un nombre de calories significativement différent ? Si vous deviez arrondir le nombre de calories aux 10 ou 50 calories les plus proches, 7! ^ 4 pourrait facilement devenir 3! ^ 4 - qui est facilement calculable par force brute
Dan Pichelman

2
Mec, tu manges trop, manger 5 repas / jour te fera de l'embonpoint.
Pieter B

Réponses:


1

Pour faire une approche plus formelle de votre problème:

Vous avez 5 listes de 7 numéros chacune. Vous devez construire 7 listes de 5 numéros chacune, et trouver la solution qui a la différence minimale entre la liste qui a la plus grande somme de nombres et celle avec le plus petit.

Si vous voulez trouver la solution optimale sans heuristique, je pense que vous n'avez pas d'autre choix que d'énumérer, mais vous n'avez pas à les énumérer toutes.

Quelle que soit la solution que vous trouvez, lorsque vous l'enregistrez comme "la meilleure trouvée jusqu'à présent", enregistrez ses performances concernant votre métrique (je crois que c'est la différence min-max). Ensuite, si une branche de solution est clairement hors route, arrêtez de l'énumérer. Protip: les jours non construits auront au mieux un nombre de calories qui est la moyenne de tous les repas restants. Donc, imaginez que vous avez des listes [10, 2, 2, 1, 1, 0, 0]pour les 5 repas, et que vous avez construit la solution 10 à chaque repas pour le jour 1. Vous savez que les jours restants seront en moyenne de 5 calories par jour, donc la différence sera d'au moins 45 et donc si vous avez trouvé précédemment une solution de, disons max - min = 10, vous n'avez pas besoin d'aller plus loin. Vous allez essayer directement un autre menu pour le jour 1.


Ce n'est pas un problème de bac. Un problème de bac n'est pas un nombre fixe de bacs ni un nombre fixe d'éléments par bac.
paparazzo

Oui, tu as raison. Je corrige ça.
Arthur Havlicek

0

C'est juste un hack mais ça vous rapproche
seulement 3 repas
Vous flopez essentiellement les repas si cela rapproche les deux jours du C # moyen

Une meilleure approche serait de retourner un volé sur Flop et d'itérer jusqu'à la fin.

Flop pourrait devenir plus intelligent. Vous pouvez être en position de ne pas floper le petit déjeuner pour floper le déjeuner et le dîner. Il peut y avoir des permutations de code en dur. Cela ressemble plus à un tri où les valeurs de flop plutôt que le tri.

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
Existe-t-il un moyen d'ajouter une explication ou des commentaires au code pour que la réponse soit plus utile / éclairante? Je pense que je comprends ce qui se passe là-dedans mais je ne peux pas en être sûr.
Adam Wells du

@AdamWells J'ai ajouté quelques commentaires. Qu'est-ce que tu ne comprends pas?
paparazzo

Il n'a tout simplement pas cliqué avec flop. Ça a du sens maintenant, merci!
Adam Wells du

Je ne peux même pas dire si c'est du code Java. C'est ça? Désolé, mes jours Java et Cx sont loin derrière moi. Où est le principal de toute façon?
Arthur Havlicek

@ArthurHavlicek Le code C #. Ils se ressemblent beaucoup.
paparazzo

0

Calculez d'abord le nombre moyen de calories par repas. Ensuite, calculez le nombre moyen de colories par jour. Ce seront les mesures que l'on peut mesurer. Triez ensuite les repas.

Maintenant, choisissez simplement les plats les plus élevés et les plus bas du genre. Si un repas se situe dans la même plage horaire, vous devrez passer au niveau le plus bas ou le plus élevé suivant jusqu'à ce que vous trouviez un repas qui n'est pas dans cette plage horaire (dîner, etc.). Faites ceci pour les 4 premiers repas (salut / bas). Au 5e repas, choisissez un repas qui vous rapproche le plus de la moyenne. Économisez le 5e repas dans un seau séparé. Rincer et répéter 7 fois.

Ce sera votre premier ensemble de repas. Ce sera assez uniforme. Si vous voulez une distribution optimale, un raffinement supplémentaire pourrait être fait avec le 5ème repas.

Parcourez le 5e seau de repas et essayez d'échanger les 5e repas entre les jours pour voir si les repas s'équilibrent encore plus. Vous devrez toujours appliquer les mêmes règles (pas plus d'un repas par fois). On peut ou non obtenir un ensemble plus uniforme. Utilisez les moyennes calculées plus tôt pour voir s'il y a une amélioration ou non. Il y aura beaucoup moins de combinaisons puisque les 4 premiers repas sont fixes en fonction de haut / bas.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.