C# C-组合数学

C# C-组合数学,c#,asp.net,combinatorics,C#,Asp.net,Combinatorics,我有一份约300件物品的清单,所有物品都有价格和分数。我需要找到最佳组合,即总价格低于X的物品中15个物品的最高总分 在我看来,最简单的方法是嵌套15个循环并检查每个可能的组合,但这需要几天的时间 在C语言中有什么“干净”的方法可以做到这一点吗 谢谢 没有一个例子是很难帮助的,但是如果我理解这个问题,这可能会有所帮助 假设你的物体看起来像这样 public class Item { public int Score { get; set; } public dec

我有一份约300件物品的清单,所有物品都有价格和分数。我需要找到最佳组合,即总价格低于X的物品中15个物品的最高总分

在我看来,最简单的方法是嵌套15个循环并检查每个可能的组合,但这需要几天的时间

在C语言中有什么“干净”的方法可以做到这一点吗


谢谢

没有一个例子是很难帮助的,但是如果我理解这个问题,这可能会有所帮助

假设你的物体看起来像这样

public class Item
{
        public int Score { get; set; }
        public decimal Price { get; set; }
}
那么下面的内容应该能帮你解决问题

var listOfObjects = new List<Item>();

var topItems = listOfObjects.Where(p => p.Price < 100).OrderByDescending(p => p.Score).Take(15);
那么下面的内容应该可以满足您的需要

var maxTotal = 1500; //for you 8000
        var objects = new List<Item>()
                      {
                          new Item() {Score = 10, Price = 100},
                          new Item() {Score = 20, Price = 800},
                          new Item() {Score = 40, Price = 600},
                          new Item() {Score = 5, Price = 300},
                      };

        decimal runningTotal = 0;
        var newList = objects
            .OrderByDescending(p => p.Score)
            .Select(p =>
                    {
                        runningTotal = runningTotal + p.Price;
                        return new ItemWithRunningTotal()
                               {
                                   Item = p,
                                   RunningTotal = runningTotal
                               };
                    })
            .OrderByDescending(p => p.RunningTotal)
            .Where(p => p.RunningTotal <= maxTotal).Take(15);

你们要找的是背包问题的解决方案。没有已知的方法可以快速完成。 您可以修改动态解决方案以最多选择maxCount项,如下所示:

public static List<Item> BestCombination(List<Item> items, int maxPrice, int maxCount)
{
    var scores = new int[items.Count + 1, maxPrice + 1, maxCount + 1];

    for (int i = 1; i <= items.Count; i++)
    {
        var item = items[i - 1];
        for (int count = 1; count <= Math.Min(maxCount, i); count++)
        { 
            for (int price = 0; price <= maxPrice; price++)
            {                    
                if (item.Price > price)
                    scores[i, price, count] = scores[i - 1, price, count];                
                else
                    scores[i, price, count] = Math.Max(
                        scores[i - 1, price, count],
                        scores[i - 1, price - item.Price, count - 1] + item.Score);
            }
        }
    }

    var choosen = new List<Item>();
    int j = maxPrice;
    int k = maxCount;
    for (int i = items.Count; i > 0; i--)
    {
        var item = items[i - 1];
        if (scores[i, j, k] != scores[i - 1, j, k])
        {
            choosen.Add(item);
            j -= item.Price;
            k--;
        }
    }            

    return choosen;
}
for (int i = 0; i <= items.Count; i++)
{
    for (int price = 0; price <= maxPrice; price++)
    {
        for (int count = 1; count <= maxCount; count++)
        {
            scores[i, price, count] = int.MinValue;
        }
    }
}

要确保在分数[,count]中是count分数或MinValue的总和。但是,如果无法精确选择maxCount,它仍然可以返回其他数量的项

您是否考虑过使用linq?出于某种原因,@T0mba会想到这一点:正如我在上面的评论中所指出的,如果您要在任何合理的时间内寻找此问题的最佳解决方案,那么您就是在做傻事。关于快速次优解的研究已经有一个多世纪了;很明显,这个问题对于从优化货架布局到为进入国际空间站的实验确定优先级的任务来说非常重要。做一个文献搜索,你会发现很多关于这个主题的论文。我现在明白了,在我读到这些问题后,我误解了问题的复杂性。@Captain0如果你在帖子中提到,在可行的时间内,这是一个次优解,我很确定它应该得到+1。你的假设是正确的,但我的问题恐怕不是很清楚:15件物品的总价格总和可能不会超过8000,个别价格并不重要。那么当总价格超过8000时会发生什么呢?是否应该使用价格较低的物品?是的,确实如此。我们只希望在不超过8000美元总成本的情况下使用15个对象时获得尽可能高的分数。
for (int i = 0; i <= items.Count; i++)
{
    for (int price = 0; price <= maxPrice; price++)
    {
        for (int count = 1; count <= maxCount; count++)
        {
            scores[i, price, count] = int.MinValue;
        }
    }
}