最もカロリーが均等な食事の取り方を選ぶ


9

私は1日に5回食事をし、週に7日あるので、各食事に7つのレシピがあり、合計35のレシピがあるとします。各レシピにはカロリー数があります。毎日、食事ごとに1つのレシピが含まれている必要があり、各レシピは特定の食事に固定されています(たとえば、ディナーにパンケーキを用意することはできません)。35のすべてのレシピがソリューションに含まれている必要があるため、週の間にレシピを繰り返すことはできません。

1日あたりのカロリー数が最も均等になるような食事の配置を見つけたいと思います。つまり、毎日消費される総カロリーの差を最小限に抑えたいと思っています。

これは宿題の問題ではありません—実際にはそうです!私はブルートフォースよりも優れたアプローチを思い付くことができず、7!^ 4の組み合わせがあります。


3
私はこれが切削ストックの問題、あるいは多分ビンのパッキング問題のバリエーションであると直感しています
Doval

明確にするために、「その日の最初の食事」の7つのレシピ、「2番目の食事」の7つのレシピ、「3番目の食事」の7つのレシピなどがあるとします。「その日の最後の食事」に「最初の食事」のレシピを割り当てますか?(別の言い方をすると、夕食にパンケーキを出してくれませんか?)
Dan Pichelman

正しい; あなたはしません。
dfaulken 2016年

2
35 種類のレシピすべてのカロリー数が大きく異なりますか?カロリーカウントを最も近い10または50カロリーに四捨五入すると、7!^ 4は簡単に3!^ 4になる可能性があります。これはブルートフォースで簡単に計算できます
Dan Pichelman

2
おい、あなたは食べ過ぎ、1日5食を食べるとあなたは太りすぎになります。
Pieter B

回答:


1

問題に対してより正式なアプローチを行うには:

それぞれ7つの番号の5つのリストがあります。それぞれが5つの数値の7つのリストを作成し、数値の合計が最大のリストと最小のリストの差が最小になるソリューションを見つける必要があります。

ヒューリスティックを使用せずに最適なソリューションを見つけたい場合は、列挙するしかありませんが、すべてを列挙する必要はありません。

どのような解決策を見つけたとしても、「これまでで最もよく見つかったもの」として登録するときは、メトリックに関するパフォーマンスを登録します(私はそれが最小-最大の違いだと思います)。次に、ソリューションブランチが明らかにこれから離れている場合は、列挙を停止します。プロチップ:ビルドされていない日には、せいぜい残りのすべての食事の平均であるカロリー数があります。したがって、[10, 2, 2, 1, 1, 0, 0]5つの食事すべてのリストがあり、1日目の食事ごとにソリューション10を作成したとします。残りの日数は1日あたり平均5カロリーであるため、差は少なくとも45となるため、以前にの解決策を見つけた場合など、max - min = 10これ以上進む必要はありません。1日目の別のメニューを直接試してみます。


ビンの問題ではありません。ビンの問題は、ビンの数やビンごとのアイテムの数が決まっているわけではありません。
パパラッツォ2016年

はい、あなたは正しいです。私はそれを修正します。
Arthur Havlicek 2016年

0

これはハックに過ぎませんが、
3食のみをクローズ
します。2日間を平均C#に近づけると、基本的に食事をフロップします。

より良いアプローチは、Flopにブール値を返し、完了するまで繰り返すことです。

フロップはより賢くなります。あなたは、昼食と夕食をフロップするために朝食をフロップしないポジションにいるかもしれません。おそらくハードコードの順列があります。これは、ソートではなく、フロップ値のソートに似ています。

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
コードに説明やコメントを追加して、答えがより役立つ/わかりやすくなるようにする方法はありますか?何が起こっているのかは理解できると思いますが、確信が持てません。
Adam Wells

@AdamWellsいくつかコメントを追加しました。何か分かりませんか?
パパラッチ

フロップでクリックされなかっただけです。理にかなっている、ありがとう!
Adam Wells

これがJavaコードかどうかさえわかりません。それは...ですか ?申し訳ありませんが、JavaとCxの時代ははるかに遅れています。とにかくメインはどこですか?
Arthur Havlicek

@ArthurHavlicekコードC#。彼らは多くの同じように見えます。
パパラッツォ2016年

0

まず、食事ごとの平均カロリー数を計算します。次に、1日あたりの平均カラー数を計算します。これらは、測定可能なメトリックになります。次に食事を分類します。

今、種類の中で最高と最低の食事を選んでください。食事が同じ時間帯にある場合は、その時間帯にない食事(夕食など)が見つかるまで、次に低いまたは高い食事に移動する必要があります。これを最初の4食(hi / low)に行います。5日目の食事で、平均に最も近い食事を選びます。5番目の食事を別のバケツに保存します。すすぎ、7回繰り返します。

これが最初の食事セットになります。これはかなり均等になります。最適な分布が必要な場合は、5回目の食事でさらに細かく調整できます。

5番目の食事バケットを通過し、5日目の食事を日ごとに交換して、食事がさらに均一になるかどうかを確認します。同じ規則を適用する必要があります(1度に1回の食事のみ)。より均一なセットが得られる場合と得られない場合があります。以前に計算された平均を使用して、改善があるかどうかを確認します。最初の4つの食事は高低に基づいて固定されているため、組み合わせははるかに少なくなります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.