C#算法 - 找到所需的最少对象数

时间:2009-12-21 16:08:11

标签: c# linq algorithm

假设我有以下代码。

var numberToGetTo = 60; 
var list = new[] {10, 20, 30, 40, 50};

我希望能够返回50& 10从列表到= 60。

如果numberToGetTo为100,我想要返回50,50。

如果numberToGetTo为85,我想返回50,40。

我想从列表中返回最少量的数字来获取“numberToGetTo”,同时保持最接近(等于或更高)的数字。

可以用Linq做这样的事吗?

6 个答案:

答案 0 :(得分:13)

这是一个名为knapsack problem的NP完全问题。这意味着,你最好的方法不会是多项式时间。您可能需要强制解决方案。

alt text

答案 1 :(得分:6)

这是一个使用Linq尽可能干净的实现。它没有尝试优化大输入的性能。

我假设你不会将此算法用于大输入,因为问题是NP-Complete,因此清晰度是正确的目标。我的算法是O(n ^ 2),并在那里递归。

    static IEnumerable<int> Knapsack(IEnumerable<int> items, int goal)
    {
        var matches = from i in items
                      where i <= goal
                      let ia = new[] {i}
                      select i == goal ? ia : Knapsack(items, goal - i).Concat(ia);

        return matches.OrderBy(x => x.Count()).First();
    }

答案 2 :(得分:2)

目前陈述的这个问题实际上是微不足道的。获得“等于或大于”目标的最简单方法是在列表中找到最大数量A,并将其粘贴在答案列表中N次,其中N是最低N,使得N * A> 1。目标。

我怀疑这不是原始海报真正想要的。如果问题被重述,以某种方式衡量各种答案的“亲密度”,并区分“更接近”的答案或数字较少的答案是否“更好”,那么它就变得更加困难。例如,如果目标是100,那么[55,55]的答案是否比[20,20,20,20,20]的答案更好或更差?

答案 3 :(得分:1)

背包问题,这可能会给你一个线索。

http://en.wikipedia.org/wiki/Knapsack_problem

我会说你可以创建一个包含实际算法的lambda表达式,但是你需要使用C#。使用'just linq'是不够的。

答案 4 :(得分:0)

这听起来类似于Subset sum problem,对于使用动态编程的小集合,可以在合理的时间内解决。这不是一个简单或常见的问题,因此您无法找到有用的Linq扩展方法:)

答案 5 :(得分:0)

我只是一起攻击这个,我相信有人可以改进。但这样做有用吗?

public class App
{
    static void Main(string[] eventArgs)
    {
        var list = new[] {10, 20, 30, 40, 50};
        var whatYouNeed = GetWhatYouNeed(list, 60, 60);
        //what you need will contain 50 & 10

       //whatYouNeed = GetWhatYouNeed(list, 105,105);
        //what you need will contain (50,50, 10)
    }

    private static IList<int> _whatYouNeed = new List<int>();


    static IEnumerable<int> GetWhatYouNeed(IEnumerable<int> list, int goal, int amountRequired)
    {   //this will make sure 20 is taken over 10, if the goal is 15. highest wins
        var intYouNeed = list.OrderBy(x => Math.Abs(amountRequired - x)).FirstOrDefault(x => x > amountRequired);
        if (intYouNeed == 0) intYouNeed = list.OrderBy(x => Math.Abs(amountRequired - x)).FirstOrDefault();
        _whatYouNeed.Add(intYouNeed);

        if (_whatYouNeed.Sum() < goal)
        {
            int howMuchMoreDoYouNeed = goal - _whatYouNeed.Sum();
            GetWhatYouNeed(list, goal, howMuchMoreDoYouNeed);
        }

        return _whatYouNeed;
    }
}

我有点懒惰,将两个值传递给GetWhatYouNeed,但你明白了。