随机重复约束的洗牌包

时间:2012-07-27 08:09:15

标签: algorithm random

我正在寻找一种算法来随机化一组长度为n的项目,其中每个项目可能有倍数(1到m)。另一个约束是,相同的项目可能不会出现在前一个项目的k个项目中。

您可能认为n远低于100,并且始终存在解决方案,即m以及k都很小。您还可以将输入更改为< item,frequency>列表如果有帮助就成对。

为了给出一些背景信息,假设我在游戏中生成任务并有一组可供选择的目标。有些目标可能会出现多次(例如"杀死老板"),但不应该彼此接近,所以只需要改变一下" bag"不好。

我可以随机播放列表,然后在跟踪项目间隔的同时迭代它,如果测试失败则从新的shuffle开始,但是我正在寻找一个更加优雅的解决方案,它也应该紧凑,实用并且可以用例如C,C ++或JavaScript。换句话说,它不应该依赖于我可能不理解或难以实现的特殊语言功能或标准库函数。但是,您可以假设最常见的列表操作(例如排序和重排)可用。

1 个答案:

答案 0 :(得分:1)

如果你想要在有效结果集上有统一的概率,那么我的预感就是你提出的拒绝方案(如果安排不好则随机播放然后重新启动)将是最容易正确编码,理解,阅读和保持以及可能相当接近最快,假设数字是大多数排列有效。

这是另一种简单的方法,基于贪婪选择有效的价值观,并希望你不要把自己打倒。如果存在许多无效排列(高mk),则完全无法找到解决方案。

shuffled = list of length n
not_inserted = {0, 1, ..., n-1}
for each item i, frequency m_i, nearness constraint k_i:
    valid = not_inserted
    do m_i times:
        choose an index j from valid
        shuffled[j] = i
        not_inserted.remove(j)
        valid.remove(j-k_i, j-k_i+1, ..., j, ..., j+k_i)

如果valid为空,则您构建的部分解决方案很糟糕,您可能需要重新启动。我猜测如果你按照m_i递减的顺序进行循环,失败的可能性就会降低。

我不确定这种方法与排序/拒绝方法相比有多少次失败(实现并为某些数字运行它会很有趣......)。我猜想在k适度高但通常较慢的情况下可能会更快,因为n << 100的洗牌速度非常快。