简单的强制数字方式

时间:2013-06-30 14:43:44

标签: algorithm set

所以我有10个号码。让我们说每个数字代表一个人的技能。如果我要创建2支5支球队,我将如何组建2支球队,以便他们的球队总和的差异很小。

7 个答案:

答案 0 :(得分:2)

使用10个数字,最简单的方法是检查所有组合并计算差异。

答案 1 :(得分:1)

这与Knapsack problem类似:您尝试将个人放入其中一个团队中,以便该团队的总和是不大于总和的一半的最大值。如果团队规模不受限制,情况就会一样。

答案 2 :(得分:0)

这是我想出的一个疯狂的想法。

时间复杂度: O(N log N)

  1. 对数字进行排序。
  2. 找出我们想要点击的集合( T )的目标总和(所有值的总和/ 2)
  3. Q =排序列表中前5个数字的集合。 Q 将是我们的最终设置,我们将反复改进。
  4. for(each element q from last element to first element of Q)
    {
     Find a number p that is not currently used
     which if swapped with the current element q   
     makes the sum closer to T but not more than T.
     Remove q from Q
     Add p to Q
    }
    return Q as best set.
    
  5. 虽然for循环看起来好像是O(N 2 ),但是可以进行二分搜索以找到数字p.So它是O(N * log N)

    免责声明:我只描述了算法。我不知道如何正式证明它。

答案 3 :(得分:0)

生成5个元素的所有组合。你将在一个团队中拥有这5个,而在另一个团队中拥有剩下的5个。比较所有结果并选择差异最小的结果。您可以使用5个for循环创建所有这些组合。

答案 4 :(得分:0)

我刚试了一下 - 不幸的是我不得不编程那个排列事物(函数next)并为每个元素调用result.fit。 可以做得更好,但为了演示它应该足够好。

var all = [ 3, 4, 5, 8 , 2, 1, 1, 4, 9, 10 ];

function sumArray(a) {
    var asum = 0;
    a.forEach(function(v){ asum += v });
    return asum;
}

var next = function(start, rest, nbr, result) {
    if (nbr < 0) {
        result.fit(start);
        return;
    }
    for (var i = 0; i < rest.length - nbr; ++i) {
        var clone = start.slice(0);
        clone.push(rest[i]);
        next(clone, rest.slice(i + 1), nbr - 1, result);
    }
};

var result = {
    target: sumArray(all) / 2,
    best: [],
    bestfit: Math.pow(2,63),    // really big
    fit: function(a) {
        var asum = sumArray(a);
        var fit = Math.abs(asum - this.target);
        if (fit < this.bestfit) {
            this.bestfit = fit;
            this.best = a;
        }
    }
}

next([], all, all.length / 2, result);
console.log(JSON.stringify(result.best));

答案 5 :(得分:0)

与大多数算法相同 - 比较126种组合。 Haskell中的代码:

inv = [1,2,3,4,5,6,7,8,9,10]

best (x:xs) (a,b)
  | length a == 5 = [(abs (sum a - sum (x:xs ++ b)),(a,x:xs ++ b))]
  | length b == 5 = [(abs (sum (x:xs ++ a) - sum b),(x:xs ++ a,b))]
  | otherwise     = let s = best xs (x:a,b)
                        s' = best xs (a,x:b)
                    in if fst (head s) < fst (head s') then s
                       else if fst (head s') < fst (head s) then s'
                       else s ++ s'

main = print $ best (tail inv) ([head inv],[])

输出:

*Main> main
[(1,([9,10,5,2,1],[8,7,6,4,3])),(1,([10,8,6,2,1],[9,7,5,4,3]))
,(1,([9,10,6,2,1],[8,7,5,4,3])),(1,([9,8,7,2,1],[10,6,5,4,3]))
,(1,([10,8,7,2,1],[9,6,5,4,3])),(1,([9,10,4,3,1],[8,7,6,5,2]))
,(1,([10,8,5,3,1],[9,7,6,4,2])),(1,([9,10,5,3,1],[8,7,6,4,2]))
,(1,([10,7,6,3,1],[9,8,5,4,2])),(1,([9,8,6,3,1],[10,7,5,4,2]))
,(1,([10,8,6,3,1],[9,7,5,4,2])),(1,([9,8,7,3,1],[10,6,5,4,2]))
,(1,([10,7,5,4,1],[9,8,6,3,2])),(1,([9,8,5,4,1],[10,7,6,3,2]))
,(1,([10,8,5,4,1],[9,7,6,3,2])),(1,([9,7,6,4,1],[10,8,5,3,2]))
,(1,([10,7,6,4,1],[9,8,5,3,2])),(1,([9,8,6,4,1],[10,7,5,3,2]))
,(1,([8,7,6,5,1],[9,10,4,3,2])),(1,([9,7,6,5,1],[10,8,4,3,2]))]

答案 6 :(得分:0)

这是Partition problem的一个实例,但对于您的小实例测试,所有组合应该足够快。