将一个数字列表分成较小的列表,其中“sum”大致相同

时间:2010-01-29 18:01:45

标签: java algorithm graph grid set

我在网格上执行大约2000次测试,每次测试都作为网格上的单独任务运行。测试确实有很大的启动时间。总执行需要500个小时,在60个节点SunGridEngine上完成不到10个小时。测试运行时间从5分钟到90分钟不等。结合没有太多智能的测试可以获得一些性能提升。我想创建大小相等的“任务”。我怎么能这样做?

(我们现在做的是:对所有测试进行排序并继续添加,直到执行时间总和大约为5小时。寻找更好的东西)

5 个答案:

答案 0 :(得分:11)

最佳地完成这项工作是NP完全的。这是partition problem的变体,这是subset sum problem的一个特例,它本身就是knapsack problem的一个特例。

在您的情况下,您可能不需要一个确切的解决方案,因此您可以使用一些启发式方法在合理的时间内获得“足够好”的东西。有关某些方法的说明,请参阅分区问题页面的Methods部分。

答案 1 :(得分:3)

您正在寻找的是k集的分区问题。

有关于k = 3的som文献,称为3分区问题。这是NP在强烈意义上完成的。

有许多启发式方法可以快速得出近似结果。

我建议你从这里开始:http://en.wikipedia.org/wiki/Partition_problem

希望这有帮助。

答案 2 :(得分:3)

这是子集和问题的a version,并且是NP完全的。最好的办法是使用一些subset-sum heuristics

答案 3 :(得分:1)

您的问题听起来有点像店铺调度问题。有各种不同的测序方法,其中一些描述here。例如,按照处理时间的递增顺序排序将最小化平均等待时间和一大堆其他措施。如果您对目标,设置时间,处理时间以及任何有助于相互依赖的内容进行详细说明。

答案 4 :(得分:0)

看看Laurence发布的链接,我想我会尝试鞭打一些东西。算法是将最长的测试分配给最短的任务列表(重复直到分配所有测试)。使用你的例子和随机测试时间,std偏差相当低,运行它几次不到2分钟(C#中的代码,但没有什么是不容易转换的):

    private static void BuildJobs()
    {
        PriorityQueue<Task> tasks = new PriorityQueue<Task>();

        //create a task list for each node
        for (int i = 0; i < 60; i++)
        {
            Task t = new Task();
            tasks.Enqueue(t);
        }

        //get the list of tests, in order from longest to shortest
        int[] testList = new int[2000];

        for (int i = 0; i < testList.Length; i++)
        {
            testList[i] = random.Next(5, 90);
        }

        Array.Sort<int>(testList);
        Array.Reverse(testList);

        // add the longest running test to the current shortest task list
        foreach (int time in testList)
        {
            Task t = tasks.Dequeue();
            t.addTest(time);
            tasks.Enqueue(t);
        }

        Debug.WriteLine(CalculateStdDev(tasks));

    }