为每个子集分割一个集合,该集合尊重其项目属性的概率

时间:2011-03-15 11:07:33

标签: c++ algorithm

对于一个小游戏(我有点被迫使用C ++,所以基于STL的解决方案在这里很有趣),我遇到了下面的问题。我想知道是否有关于这个主题的文献我可以阅读,或者是巧妙的实施。

独特物品{E1,E2,E3}的集合S,每个物品E具有一组属性,{P1,P2,P3 ...}
该集合应分为S1,S2,S3,S4。它定义了S1..4必须具有多大的精确度。我们可以假设集合可以正确地分成这些大小以解决问题的其余部分。

现在,对于S1,可以出现许多约束,{C1,C2 ..},它们指定例如,没有具有属性P1的项目可能出现在其中。另一个约束可能是它应该支持具有属性P2的因子为0.8的项(我们可以假设这些类型的约束针对每个属性的所有子集进行了规范化)。

“加权”并不难实现。我只是用一些候选数字填充一些数组,权重较高的数组在这个数组中表示得更多。然后我选择数组的随机元素。数组的大小决定了准确性/粒度(在我的例子中,一个小数组就足够了)。

问题是禁止出现一些项目。它很容易导致S中的一个项目需要放置在子集S1,S2,S3或S4中的一个中的情况,但是由于子集全部已满或者不满足,因此不再发生这种情况。完全具有此项无法出现在集中的特定约束。所以你必须回溯展示位置。过于频繁地这样做可能会过多地违反加权概率。

如何调用此问题,或者它是否容易映射到另一个(可能是NP)问题?

编辑:示例:

S = {A,B,C,D,E,F,G,H,I,J,K,L,M}

S1 = [具有VOWEL的概率为0.8,不能有I或K,SIZE = 6] S2 = [0.2有VOWEL的概率,不能有M,B,E,SIZE = 7]

现在,假设我们开始填写FOR(LETTER IN S):

LETTER A,根据属性约束创建一个填充数组(0.8 vs 0.2):
[1,1,1,1,1,1,1,2,2] 从该数组中选择一个随机元素:1。

现在,将A放入S1。

例如,对于字母I,唯一的候选者是2,因为S1有一个我不能出现在其中的约束。

继续这样做,最终你可能最终得到:
C = {M} //再分发一封信

S1 = A,B,D,E,F,G
S2 = C,F,G,I,K,L

现在,在哪里放置M?我不能被放置在S1中,因为它已经满了,并且它不能放在S2中,因为它有一个约束,M不能放在其中。
唯一的方法是回溯一些位置,但是我们可能会过多地加重加权分布(f.i.,给S2一个S1的元音,它绕着自然分布翻转)

请注意,当更多的子集在播放时,这会变得稍微复杂一些(在某种意义上需要更多的回溯),而不仅仅是2。

2 个答案:

答案 0 :(得分:1)

这与具有硬约束和软约束的约束满足问题(CSP)相似。有几种标准算法,但是如果它们适用于您的特定问题实例,则必须检查。

检查wikipedia是否为初学者。

答案 1 :(得分:1)

这个启发式怎么样:

1考虑到由于约束和完整集的限制,找到仅满足单个集合标准的任何元素并将它们放在那里。如果在任何时候,其中一个插入导致集合变满,则重新评估元素以满足仅一个集合的条件。

2现在只查看可以恰好适合两组的元素。对于每个元素,如果添加了该元素,则计算每个集合所需概率的差异。将元素插入到集合中,其中插入导致最佳短期结果(第一个拟合/贪婪算法)。如果插入填充集合,则重新评估元素以满足仅两个集合的条件

3继续使用适合3组,4组...... n套的元素。

此时,所有元素将被置于满足所有约束的集合中,但概率可能不是最佳的。您可以继续通过在集合之间交换元素(仅允许不违反约束的交换),通过在描述所有概率满足程度的函数上使用梯度下降或随机重启山峰clibing算法。这往往趋向于最优解,但不能保证满足它。继续,直到您满足您的要求,在可接受的金额内,或直到达到固定的时间限制,或直到可能的改进低于设定的阈值。