Yemeklerin en kalorili eşitliğini seçme


9

Günde beş öğün yediğimi ve haftada yedi gün bulunduğundan, toplamda 35 tarif için her öğün yedisi için tariflerim olduğunu varsayalım. Her tarifin bir kalori sayımı vardır. Her gün yemek başına bir tarif içermelidir ve her tarif belirli bir yemeğe sabitlenmiştir (örneğin, akşam yemeği için krep yiyemezsiniz). 35 tarifin hepsi çözelti içinde olmalıdır, bu yüzden bir tarif hafta boyunca tekrarlanamaz.

Günde en eşit kalori miktarını verecek öğün düzenini bulmak istiyorum - yani, günden güne tüketilen toplam kalori farkını en aza indirmek istiyorum.

Bu bir ev ödevi sorunu değil - aslında doğru! Kaba kuvvetten daha iyi bir yaklaşım bulamıyorum ve çok fazla 7! ^ 4 kombinasyonu var.


3
Bu, kesme stoku probleminin veya belki de bin paketleme probleminin bir varyasyonu olduğunu hissettim .
Doval

Açıklığa kavuşturmak için - "günün ilk yemeği" için 7, "2. yemek" için 7, "3. yemek" için 7, ve benzeri var mı? Hiç "günün son yemeği" ne bir "ilk yemek" tarifi atadı? (Başka bir deyişle, akşam yemeği için krep servis eder misiniz?)
Dan Pichelman

Doğru; yapmazdın.
dfaulken

2
35 tarifin hepsinde önemli ölçüde farklı kalori sayımı var mı? Kalori sayımlarını en yakın 10 veya 50 kaloriye yuvarlayacak olsaydınız, 7! ^ 4 kolayca kaba kuvvetle kolayca hesaplanabilen 3! ^ 4 olabilir
Dan Pichelman

2
Dostum, çok fazla yiyorsun, günde 5 öğün yemek fazla kilo alacak.
Pieter B

Yanıtlar:


1

Sorununuza daha resmi bir yaklaşım yapmak için:

Her biri 7 numaradan oluşan 5 listeniz var. Her biri 5 sayıdan oluşan 7 liste oluşturmanız ve en büyük sayıya sahip olan liste ile en küçük olanı arasındaki minimum farkı içeren çözümü bulmanız gerekir.

Sezgisel olmayan en uygun çözümü bulmak istiyorsanız, numaralandırma dışında çok az seçeneğiniz olduğuna inanıyorum, ancak hepsini numaralandırmak zorunda değilsiniz.

Hangi çözümü bulursanız bulun, "şimdiye kadarki en iyi bulundu" olarak kaydettiğinizde, metriğinizle ilgili performansını kaydedin (min-max fark olduğuna inanıyorum). Daha sonra, bir çözüm dalı bu yoldan açıkça yoldaysa, numaralandırmayı durdurun. Protip: İnşa edilmemiş günler en iyi kalan kalorilerin ortalaması olan bir kalori sayısına sahip olacaktır. Yani, [10, 2, 2, 1, 1, 0, 0]tüm 5 öğün için listeleriniz olduğunu ve 1 gün boyunca her öğünde 10 çözeltisini oluşturduğunuzu düşünün. Kalan günlerin günde ortalama 5 kalori olacağını biliyorsunuz, bu yüzden fark en az 45 olacak ve Daha önce bir çözüm buldunuz, diyelim ki, max - min = 10daha ileri gitmenize gerek yok. 1. gün için doğrudan başka bir menü deneyeceksiniz.


Bir çöp kutusu sorunu değil. Bir bölme sorunu, bölme başına sabit sayıda kutu değil, bölme başına sabit sayıda öğe değildir.
paparazzo

Evet haklısın. Bunu düzelteceğim.
Arthur Havlicek

0

Bu sadece bir hack ama size yakın alacak
Sadece 3 öğün
Eğer temelde iki gün ortalama C # yakın yaparsanız, yemek flop

Daha iyi bir yaklaşım Flop'ta bir boole döndürmek ve tamamlanana kadar tekrarlamak olacaktır.

Flop daha akıllı olabilir. Öğle ve akşam yemeğini flop etmek için kahvaltıyı flop yapmama pozisyonunda olabilirsiniz. Sabit kod permütasyonları olabilir. Bu daha çok sıralama yerine flop değerlerinin bulunduğu bir sıralama gibidir.

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
cevabın daha yararlı / aydınlatıcı olmasını sağlamak için koda açıklama veya bazı yorumlar eklemenin bir yolu var mı? Sanırım orada neler olduğunu anlıyorum ama emin olamıyorum.
Adam Wells

@AdamWells Birkaç yorum ekledim. Neyi anlamıyorsun?
paparazzo

Sadece flop ile tıklamadı. Şimdi mantıklı, teşekkürler!
Adam Wells

Bunun Java kodu olup olmadığını bile söyleyemem. Bu mu ? Maalesef, Java ve Cx günlerim geride kaldı. Zaten ana nerede?
Arthur Havlicek

@ArthurHavlicek C # kodu. Aynı görünüyorlar.
paparazzo

0

İlk önce öğün başına ortalama kalori sayısını hesaplayın. Sonra günlük ortalama renk sayısını hesaplayın. Bunlar, kişinin ölçebileceği ölçümler olacaktır. Sonraki yemekleri sıralayın.

Şimdi sadece en yüksek ve en düşük yemekleri sıralamada seçin. Bir yemek aynı zaman dilimindeyse, o zaman diliminde (akşam yemeği vb.) Olmayan bir yemek bulana kadar bir sonraki en düşük veya en yüksek seviyeye gitmeniz gerekecektir. Bunu ilk 4 öğün (yüksek / düşük) için yapın. 5. öğünde ortalamaya en yakın yemeği seçin. 5. yemeği ayrı bir kovaya kaydedin. Durulayın ve 7 kez tekrarlayın.

Bu ilk yemek setiniz olacak. Bu oldukça eşit olacak. En iyi dağılımı istiyorsanız, 5. öğünle biraz daha iyileştirme yapılabilir.

5. yemek kovasına gidin ve yemeklerin daha da dışarı çıkıp çıkmadığını görmek için günler arasında 5. yemekleri değiştirmeyi deneyin. Yine de aynı kuralları uygulamanız gerekecek (her seferinde birden fazla yemek değil). Daha eşit bir set elde edilebilir veya edilmeyebilir. Bir iyileşme olup olmadığını görmek için hesaplanan ortalamaları daha önce kullanın. İlk 4 öğün yüksek / alçak olarak sabitlendiği için çok daha az kombinasyon olacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.