问题是:我有一个包含随机数的数组。我应该将它们分成块,这样在每个块中,所有元素的总和不大于给定的N.我以为我可以简单地用扫描解决这个问题,但是有一个令人讨厌的错误,我不知道如何有效解决
例如,我尝试如下:N=8
,数组为:
{2, 3, 1, 4, 4, 1, 6}
执行包容性总和扫描:
{2, 5, 6, 10, 14, 15, 21}
然后按N=8
进行简单的整数除法,得到以下分区:
{0, 0, 0, 1, 1, 1, 2}
然后我意识到存在一个错误,即第二个块中所有元素的总和是4+4+1=9
而不是8
,因为通过使用整数除法,我假设所有元素的总和在第一个街区必须是8.
正确的分区应该是:
{0, 0, 0, 1, 1, 2, 2}
我试图遍历列表并重新划分边界点,但我的并行实现比串行实现慢。你碰巧知道这个问题的有效并行算法吗?
答案 0 :(得分:1)
不是从扫描开始,而是从并行计算每个节点n(i)开始,后续节点n(j)的索引是什么,它结束了从n(i)开始并且总和小于或者的子序列等于8.(步骤1)
这是一个由并行的每个线程操作的相当短的循环,它将为您提供一系列索引。
{2,3,1,4,4,1,6}
{2,3,3,4,5,6,6}(步骤1结束)
然后并行遍历从节点0开始的链表;考虑在步骤1中为0计算的索引之后的节点的后继0;基本上这是解决方案中的箱的起始点的链接列表。
[在log(n)步骤中并行计算并且n log(n)工作矩阵,其在位置(i,k)为节点i提供距节点i 2 ^ k跳的节点。
{0,1,2,3,4,5,6}
3,4,4,5,6, - , -
5,6,6, - , - , - , -
- , - , - , - , - , - , -
从节点0开始并行地计算每个节点的位置,并连续唤醒更多节点以用于log(n)整个并行步骤。
0, - , - , - 1, - 2, -
分散并获取起点列表](步骤2)
{0,3,5}
现在与此序列并行分散一个0和1的新序列,如下所示;从0开始(步骤3)
{0,0,0,1,0,1,0}
最后应用包容性扫描以获得结果。 (第4步)
在你的例子中:
{2,3,1,4,4,1,6}
{2,3,3,4,5,6,6}(步骤1)
{0,3,5}(第2步)
{0,0,0,1,0,1,0}(步骤3)
{0,0,0,1,1,2,2}(步骤4)
如果原始序列中没有0,则initail循环具有常量步和线性工作,因此您需要支付列表遍历,即log(n)步和扫描。如果你在原始序列中有零,但数字是随机选择的自然数,那么在受影响的SM上有很多长零序列创建坏的最坏情况的概率仍然相当低。只要自然数(随机选择)随机选择,大于8的常数就不会有太大差别;在实践中,出于类似的推理,也不应该成为输入的一部分。
如果您涉及负数,那么这个解决方案不可行,但可能是朝着改进的通用解决方案迈出的一步。
我可以看到有一个更简单的解决方案的空间,我已经把一些已知的构建块放在一起。据我所知,解决方案仍然是正确和切实可行的,使用已知的模式,我们至少知道有一个。