设备包含一系列位置,其中一些包含我们想要定期读取的值。
我们想要定期阅读的位置列表还指定了我们想要阅读它们的频率。允许读取比指定频率更频繁的值,但不能频繁读取。
单个读取操作可以从阵列中读取连续的位置序列,因此可以从一个读取操作返回一组多个值。在单个操作中可以读取的最大连续位置数是M.
目标是对位置进行分组,以便最大限度地缩短读取操作的时间平均次数。如果有多种方法可以做到这一点,那么决胜局就是尽量减少时间平均读取位置的数量。
(如果执行此操作的算法允许对位置列表进行增量更改,则会获得奖励积分 - 即向列表添加或从列表中删除一个位置不需要从头开始重新计算分组!)
我将尝试用M = 6的一些例子来澄清这一点。
下图显示了位置数组。数字代表该位置的所需读取周期。
| 1 | 1 | | | 1 | | | | | | 5 | | 2 |
\-------------------/ \-----------/
group A group B
在第一个例子中,每秒读取一组A,每2秒读取一组B.请注意,应该每隔5秒读取一次应该每5秒读取一次的位置 - 这很好。
| 1 | | | | | 1 | 1 | | 1 |
\-----------------------/\----------/
group A group B (non-optimal!)
这个例子显示了我最初的简单算法的失败,即填充第一组直到完全然后再启动另一组。以下分组更为理想,因为尽管每秒的组读取次数相同,但在这些组中读取的位置数量较少:
| 1 | | | | | 1 | 1 | | 1 |
\---/ \---------------/
group A group B (optimal)
最后,一个例子,其中三个组优于两个:
| 5 | | | | | 1 | 1 | | | | | 5 |
\-----------------------/\----------------------/
group A group B (non-optimal)
此解决方案每秒需要两次组读取。更好的解决方案如下:
| 5 | | | | | 1 | 1 | | | | | 5 |
\---/ \-------/ \---/
group A group B group C
这需要每5秒进行两次读取(A组和C组)加上每秒一次(B组):每秒1.4组读数。
编辑:(如果你允许读取是非周期性的,那么这个例子有一个更好的解决方案。在第1秒,读取第一个解决方案的两个组。在第2个,第3个,第4个和第5个读取组B第二个解决方案。重复。这导致每秒1.2组读取。但是我将不允许这样做,因为它会使负责调度读取的代码变得更加复杂。)
我查找了聚类算法,但这不是聚类问题。我还发现了Algorithm to allocate a list of numbers to N groups under certain condition,它指的是'Bin packing'问题,但我认为不是这样。
顺便说一句,抱歉这个模糊的标题。我想不出简洁的描述,甚至是相关的搜索关键词!2010年9月28日新增示例:
这与前面的示例类似,但所有项目都以相同的速率更新。现在两组比三组好:
| 1 | | | | | 1 | 1 | | | | | 1 |
\-----------------------/\----------------------/
group A group B (optimal)
我开始尝试了解如何实施迭代改进。假设分组算法提出:
| 1 | | | | | 1 | 1 | | | | | 1 | 1 | | | | | 1 |
\---/ \-------/ \-------/ \---/
group A group B group C group D (non-optimal)
\-----------------------/\----------------------/\----------------------/
group A group B group C (optimal)
这可以改进为三个相邻的组,每组6. Rex建议(下面的评论)我可以尝试将三元组组合成对。但在这种情况下,我必须将一个四重奏组合成一个三元组,因为没有合法的中间安排,其中A + B + C(或B + C + D)可以重新排列成一对,留下D原样。 / p>
我原本以为这表明在一般情况下无法保证可以通过进行本地修改从现有的有效解决方案中创建新的有效解决方案。这意味着可以使用诸如模拟退火,遗传算法等算法来尝试改进次优解。
但雷克斯指出(下面的评论)你总是可以将现有的一组分成两组。尽管这总是会增加成本函数,但所有这些都意味着解决方案需要超出其局部最小值才能达到全局最小值。
答案 0 :(得分:4)
这个问题与添加类似NP完全问题的新项目具有相同的不稳定性,所以我认为它也是一个。由于我怀疑你想要的东西运行得相当好而不是为什么它很难证明,我将专注于一个算法来给出一个近似的解决方案。
我会通过将此转换为图表来解决此问题,如果必须每秒读取N次,则将二进制值的值设为1 / N,并将宽度为M(例如6)的图形模糊,达到峰值原版的。 (对于6,我可以使用加权(1/6 1/5 1/4 1/3 1/2 1 1/2 1/3 1/4 1/5 1/6)。)然后在当地投掷垃圾箱最大值(按距离分开对,如果可以的话,首先覆盖最大对的最大对)。现在,您将涵盖大部分最重要的价值观。然后通过扩展现有读取来捕获任何缺失的组,或者在必要时添加新读取。根据结构,您可能希望通过在读取之间移动位置来添加一些细化,但如果您很幸运,甚至不需要。
由于这实际上是一种局部算法,如果你跟踪模糊图形,你可以相当容易地添加新项目并在本地重新进行峰值覆盖(以及本地细化)。
为了看看这对你的数据有何影响,两组案例看起来像是(乘以60,所以我不必跟踪分数权重)
60 30 20 15 12 10 00 00 00 <- contribution from left-most location
10 12 15 20 30 60 30 20 15 <- second
00 10 12 15 20 30 60 30 20 <- third
00 00 00 10 12 15 20 30 60 <- rightmost
--------------------------
70 42 47 50 74 B5 B0 80 95 (using "B" to represent 11)
^^ ^^ ^^ Local maxima
------------- -------
dist=6 dist=4
|===========| <- Hit closely-spaced peaks first
|==| <- Then remaining
所以我们已经完成了,解决方案是最佳的。
对于三组示例,将“5”加权为“1/5”并将所有内容乘以300,这样就没有分数,
060 030 020 015 012 010 000 000 000 000 000 000 <- from 5 on left
050 060 075 100 150 300 150 100 075 060 050 000 <- 1 on left
000 050 060 075 100 150 300 150 100 075 060 050 <- on right
000 000 000 000 000 000 010 012 015 020 030 060 <- 5 on right
-----------------------------------------------
110 140 155 190 262 460 460 262 190 155 140 110
|=======| <- only one peak, grab it
=== === <- missed some, so pick them back up