考虑我有一些数字。例如{1,2,3,7,8,9,11,15,16}。我需要的是将该组分成尽可能少的子集,并且最低和最高数之间的差异小于9。
从我的例子中,它将是例如:
{1,2,3,7,8},{9,11,15,16}
我需要这个来优化通过Modbus的“读取多个寄存器”请求的数量
我已经尝试将集合拆分为具有连续数字的子集而不是将它们合并,但它并不理想,因为它会将此返回给我:
{1,2,3},{7,8,9,11},{15,16}或{1,2,3},{7,8,9},{11,15,16} >
正如你所看到的,这种方法给了我三个子集而不是两个子集
有没有可用的算法?
感谢
答案 0 :(得分:3)
贪婪的方法怎么样,即将元素从左边插入到集合中,当你超越所需的差异时,创建一个新的集合。
因此,1, 2, 3, 7, 8, 9, 11, 15, 16
:
你从1.开始
2-1 = 1< 9,所以加2.
3-1 = 2< 9,所以加3.
7-1 = 6< 9,所以加7.
8-1 = 7< 8-1 9,所以加8
9-1 = 8< 9,所以加9.
11-1 = 10> 9,所以创建一个新的集
15-11 = 4< 9,所以加15
16-11 = 5< 9,所以加16。
输出:{1, 2, 3, 7, 8, 9}, {11, 15, 16}
。
注意:强>
如果元素不必排序,我们可以先对它们进行排序。
如果这些子集不必连续,则不会产生差异,因为从有序输入中选择连续集始终优于非连续集。
如果元素不必排序和,则子集必须是连续的,这会稍微改变问题。
最佳性证明:
设S是该算法为某些任意输入产生的集合赋值。
进行任何设定作业T。
令S i 为第i组S.
令T i 为第i组T。
设S i-size 是第i组S的大小。
令T i-size 为第i组T的大小。
假设S和T不同,则对于某些S i 和T i ,S i-size != T I-大小子>。具体来说,选择第一组i
,其中两者不同。
所以S i-size &gt; T i-size 或S i-size &lt; Ť<子> I-大小子>
j&gt;我是不可能的,因为这个算法从一开始就采用尽可能多的元素。
如果j < i,S i + 1 的第一个元素将大于T i + 1 的第一个元素,并且由于算法是贪婪的,S i + 1 至少包括S i 中尚未包含的T i + 1 的所有元素。
现在,由于上述原因,S i + 2 的第一个元素同样会大于T i + 2 的第一个元素,因此S i + 2 将至少包括先前S组中尚未包括的T i + 2 的所有元素。类似地,对于S和T的其余组,因此存在在T中至少与S中的数量一样多。
因此,该算法产生的设定分配不会比任何其他分配更差。因此它是最佳的。