假设我每天吃五顿饭,并且由于一周中有七天,我每顿饭有七个食谱,总共35个食谱。每个食谱都有卡路里计数。每一餐每一天都必须包含一个食谱,并且每个食谱都固定于特定的一餐(例如晚餐不能吃煎饼)。解决方案中必须包含所有35种食谱,因此一周内不能重复食谱。
我想找到可以每天提供最多卡路里数的膳食安排-也就是说,我想使每天消耗的总卡路里之间的差异最小化。
这不是作业问题,这是事实!我无法提供比暴力破解更好的方法,并且有7!^ 4个组合,这很多。
假设我每天吃五顿饭,并且由于一周中有七天,我每顿饭有七个食谱,总共35个食谱。每个食谱都有卡路里计数。每一餐每一天都必须包含一个食谱,并且每个食谱都固定于特定的一餐(例如晚餐不能吃煎饼)。解决方案中必须包含所有35种食谱,因此一周内不能重复食谱。
我想找到可以每天提供最多卡路里数的膳食安排-也就是说,我想使每天消耗的总卡路里之间的差异最小化。
这不是作业问题,这是事实!我无法提供比暴力破解更好的方法,并且有7!^ 4个组合,这很多。
Answers:
要对问题采取更正式的方法:
您有5个包含7个数字的列表。您需要构建7个列表,每个列表包含5个数字,然后找到在最大数字和最小数字之间的差异最小的解决方案。
如果您想找到没有启发式的最佳解决方案,我相信您除了枚举外别无选择,但您不必全部列举。
无论找到什么解决方案,当您将其注册为“迄今为止最好的”时,请针对您的指标注册其性能(我相信这是最小-最大差异)。然后,如果解决方案分支显然不在此范围之内,请停止枚举。提示:非住宿日的卡路里计数最多为所有剩余膳食的平均值。因此,想象一下,您拥有[10, 2, 2, 1, 1, 0, 0]
所有5餐的清单,并且在第1天的每餐中构建了10个解决方案。您知道剩余的天平均每天5卡路里,因此差异至少为45,所以如果您以前找到了的解决方案,例如max - min = 10
,您无需再进行任何操作。您将在第一天直接尝试其他菜单。
这只是一个hack,但可以使您关闭
仅三餐
你基本上翻牌的饭菜,如果它使这两天更接近平均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;
}
}
首先计算每餐的平均卡路里数。然后计算每天的平均色料数。这些将是可以衡量的指标。接下来整理饭菜。
现在,只选择最高和最低的饭菜。如果在同一时段进餐,则您必须转到下一个最低或最高的时段,直到找到不在该时段内的餐点(晚餐等)。前四餐(高/低)进行此操作。在第五餐时,选择一餐能使您最接近平均水平的餐点。将第五餐保存到单独的桶中。冲洗并重复7次。
这将是您最初的饭菜。这甚至会很漂亮。如果您想要最佳的分配,可以在第5餐时做一些进一步的细化。
通过第五餐桶,尝试在两天之间交换五餐,以查看餐点是否均匀。您仍然必须应用相同的规则(每次不超过一顿饭)。一个人可能会或可能不会得到更均匀的设置。尽早使用计算出的平均值来查看是否有改善。因为前4餐是根据高/低固定的,所以组合会少很多。