有没有一种有效的方法来找到集合S中所有有序的元素排列,它们加起来为N?

时间:2016-10-09 23:36:23

标签: c# .net algorithm linq optimization

这就是我的意思。假设S = {1, 4}N = 5。集S中元素的有序排列就像

{1}, {4}, {1,1}, {1,4}, {4,1}, {4,4}, {1,1,1}, ....

和总计N的那些

{1,4}, {4, 1}, {1,1,1,1,1}

我想要一种能够有效找到这些算法的算法。

我的“蛮力”方式就像

static IEnumerable<IEnumerable<int>> OrderedArrangements(IEnumerable<int> nums, int k)
{
    var singles = nums.Select(i => new int[] {i} );
    var cumulative = singles;
    for(int j = 2; j <= k; ++j)
    {
        var last = cumulative.Where(list => list.Count() == (j - 1));
        var next = from x in singles
                   from y in last
                   select x.Concat(y);
        cumulative = cumulative.Concat(next);           
    }
    return cumulative;
}

然后

int sumToN = OrderedArrangements(new int[] {1, 4}, N)
                .Where(x => x.Sum() == N);

但我想知道是否有一种明显且更有效的方法来做到这一点。

2 个答案:

答案 0 :(得分:1)

如果上面的答案不够清楚,你可以尝试直接递归,例如

     ...
    /       \
   (1)     (4)          
  /  \     /  \
 (1)(4)   (1)(4)
static void f(int sum, int n, String str, int[] arr){
    if (n == sum){
        Console.WriteLine(str);
        return;
    }
    if (n > sum) return;
    for (int i = 0; i < arr.Length; i++){
        f(sum, n + arr[i], str + arr[i].ToString(), arr);
    }
}

static void Main(string[] args){
    int[] arr =  { 1, 4 };
    f(5, 0, "", arr);
}

问题中sumNn初始化为0str初始化为""和{{1}你的问题是arr

输出:

S

答案 1 :(得分:0)

这对我有用:

static IEnumerable<IEnumerable<int>> OrderedArrangements(IEnumerable<int> nums, int k)
{
    return
        k <= 0
            ? new [] { Enumerable.Empty<int>() }
            : nums
                .SelectMany(
                    n => OrderedArrangements(nums, k - n),
                    (n, ns) => new [] { n }.Concat(ns))
                .Where(ns => ns.Sum() == k);
}

OrderedArrangements(new [] { 1, 4 }, 5)的结果是:

result

我运行了这个性能测试代码:

Func<Func<IEnumerable<IEnumerable<int>>>, double> measure = f =>
{
    var sw = Stopwatch.StartNew();
    var result = f();
    sw.Stop();
    return sw.Elapsed.TotalMilliseconds;
};

var n = 200;
var a = 0.0;
var b = 0.0;
for (var i = 0; i < n; i++)
{
    a += measure(() => OrderedArrangements_A(new [] { 1, 4, 9, 13 }, 50000));
    b += measure(() => OrderedArrangements_B(new [] { 1, 4, 9, 13 }, 50000));
}

OrderedArrangements_A是OP的代码,OrderedArrangements_B是我的。

“A”平均为15.6ms,“B”平均为0.004ms。我的代码运行速度提高了大约3,895倍。