C#查找适合某些插槽的项目的最大值

时间:2014-01-03 02:42:28

标签: c# algorithm math knapsack-problem

所有

我有一个问题包围我如何找到2个值之间的理想关系,同时还必须将这些项目放入某个位置。老实说,我甚至不知道从哪里开始。我研究了背包问题,但没有位置要求。

示例:

我有50美元用于食物。我需要吃4餐(早餐,午餐,晚餐和小吃 - 可以是早餐或午餐)。每餐有4个?性能;名称,槽位,卡路里和成本。我的目标是在保持50.00美元分配的同时吃掉最多的卡路里。

class Meal
{
    public enum MealType
    {
        Breakfast = 1,
        Lunch = 2,
        Dinner = 3
    }

    public string Name { get; set; }
    public MealType Type { get; set; }
    public int Calories { get; set; }
    public decimal Cost { get; set; }

    public Meal(string _name, MealType _type, int _calories, decimal _cost)
    {
        Name = _name;
        Type = _type;
        Calories = _calories;
        Cost = _cost;
    }
}

我可以从电子表格或其他来源读取并为每条记录创建一份膳食并将其添加到列表中。我不知道如何阅读我的清单(或任何收藏品),并找到4餐的最大卡路里组合,同时坚持要求餐#1必须是#34;早餐",餐#2必须是"午餐"类型#3必须是"晚餐"类型,#4;#4;类型#34;早餐"或者"午餐"。关于从哪里开始的任何想法?感谢。

更新

我最终得到了这个 - 尽管我确定它效率不高,特别是随着输入列表的增长。这是一个可怕的代码(我显然还定义了一个不包含的Menu类):

        List<Meal> allMeals = Meal.GetMeals();
        List<Meal> allBreakfast = new List<Meal>();
        List<Meal> allLunch = new List<Meal>();
        List<Meal> allDinner = new List<Meal>();
        List<Meal> allSnack = new List<Meal>();

        foreach (Meal meal in allMeals)
        {
            if (meal.MealType == Meal.MealType.Breakfast)
            {
                allBreakfast.Add(meal);
                allSnack.Add(meal);
            }
            else if (meal.MealType == Meal.MealType.Lunch)
            {
                allLunch.Add(meal);
                allSnack.Add(meal);
            }
            else if (meal.MealType == Meal.MealType.Dinner)
            {
                allDinner.Add(meal);
            }
        }

        foreach (Meal breakfast in allBreakfast)
        {
            foreach (Meal lunch in allLunch)
            {
                foreach (Meal dinner in allDinner)
                {
                    foreach (Meal snack in allSnack)
                    {
                        if (snack == breakfast || snack == lunch)
                        {
                            continue;
                        }
                        currMenu = new Menu(breakfast, lunch, dinner, snack);

                        if (currMenu.Cost < Menu.MaxCost && (maxMenu == null || currMenu.Calories > maxMenu.Calories))
                        {
                            maxMenu = currMenu;
                        }
                    }
                }
            }
        }

2 个答案:

答案 0 :(得分:0)

在这种情况下,如果您不熟悉复杂算法,可以尝试在时间和内存空间仍然可行的强力算法。

我们有4套存储记录:A,B,C,D(A:早餐,B:午餐,C:晚餐,D = A + B)

我们的目标是找到Ai,Bj,Cu,Dv以便:

1. Ai.cost + Bj.cost + Cu.cost + Dv.cost <=50 
2. Ai.calo + Bj.calo + Cu.calo + Dv.calo is maximum

实际上,我们只计算2位小数 - &gt;价格范围是0.00 - > 50.00,即5000例

1. Find all cost combination of Ai + Bj (<=50) store into array AB.
     if (Ai1  + Bj1 == Ai2 + Bj2), just take combination have higher calories.
=> Complexity: O(|A| * |B|)


2. Find all cost combination of Cu + Dv (<=50) store into array CD with the same process as for AB
=> Complexity: O(|C| * |D|)
Note: size of AB and CD is 5000 elements

3. Find all combination AB[p] + CD[q] which cost is under 5000 and we can know which one got highest calories.
=> Complexity: O(|AB| * |CD| ) = O(5000 * 5000)

总的来说,如果使用暴力,时间复杂度为O(5000 * 5000)+ O(|一个类别| ^ 2的spreadSheet大小)。

如果spreadSheet大小<= 5000并且您不熟悉算法,则可以使用这种简单方法。否则,只需前进,算法很有趣:)

答案 1 :(得分:0)

好的,所以如果您已经阅读了背包问题,并且仍然不知道如何解决它,那么您可以考虑以下内容

这个想法很简单,数组结果包含任何膳食组合可以达到的所有金钱价值。所以首先,当你不买任何东西时,只能得到结果[50]。

迭代所有选择,从早餐到零食检查可以达到的值,我们可以慢慢地建立价值表。例如,如果早餐有三个价格(1,2,3),那么下一个州只能是(50-1),(50-2),(50-3)等等。在数组结果中,我们存储可以创建的卡路里的最大值。因此,如果一个早餐套餐的费用为3,卡路里2和另一套套餐的费用为3卡路里,那么结果数组索引(50 -3)的值为4。

最后,在扫描完所有状态后,存储在结果数组中的值是可以产生的卡路里的最大值。

            int money = 50;// your initial money
            int[] result = new int[money + 1];
            for (int i = 0; i < result.length; i++) {
                result[i] = -1;//-1 means cannot reach
            }
            result[50] = 0;//Only 50 can be reached at first
            List<Meal>[] list = new List[4]; // Array for all 4 meals
                                             // 0 is Breakfast
                                             // 1 is lunch
                                             // 2 for dinner
                                             // 3 for snack

            for (int i = 0; i < 4; i++) {//Iterating from breakfast to snack
                int[] temp = new int[money + 1];//A temporary array to store value
                for (int j = 0; j < result.length; j++) {
                    temp[j] = -1;
                }
                for (int j = 0; j < result.length; j++) {
                    if (result[j] != -1) {//For previous value, which can be reached
                                          //Try all posibilites
                        for (int k = 0; k < list[i].size(); k++) {
                            int cost = list[i].get(k).cost;
                            int energy = list[i].get(k).energy;
                            if (cost <= result[j]) {
                                temp[j - cost] = max(temp[j - cost], result[j] + energy);
                            }
                        }
                    }
                }
                result = temp;//Need to switch these arrays.
            }
            int max = 0;
            for(int i = 0; i < result.length; i++){
                max = max(max, result[i]);
            }
            System.out.println(max);