我有400个球,其中100个是红色,40个是黄色,50个是绿色,60个是蓝色,70个是紫色,80个是黑色。 (相同颜色的球是相同的)
我需要一个有效的改组算法,这样在洗牌之后,球就在列表中,并且
任何连续的3个球的颜色不同。例如,我不能有“红色,红色,红色,黄色......”
而且,所有排列都“同样”可能发生。 (好吧,如果效率与无偏见的权衡取得足够好,我不介意比无偏见更有效率。)
我试图改编Fisher-Yates-Knuth,但结果并不理想。
为什么Fisher-Yates不够好?由于FY采用蒙特卡罗逆变换。并且输出分布以不同的方式处理相同的颜色球,即它会根据我的需要产生偏差结果。
而且,天真的想法是过滤掉/回溯整个空间的所有不良排列。当限制很强时,比方说,如果我们只有300个球,其中100个是红色的,那么在进行适当的排列之前会有太多的后跟踪/失败。
所以,最终,我希望能够遍历所有良好的排列。但是,由于有效排列的数量太大,我只能随机抽样其中一些。
答案 0 :(得分:2)
据我了解,FYK算法在数组中交换随机位置。为什么你不能像我在伪代码中描述的那样产生颜色?
public IEnumerable<Color> GetColors()
{
int count = 400;
// queue or another data structure to hold the last generated colors
Queue<Color> lastColors = new Queue<Color>();
var availableColor = new Dictionary<Color, int> {
{Red, 100}, {Yellow, 40}, ...
};
Color nextColor = null;
while(count > 0)
{
do {
/* randomly pick from color buckets */
nextColor = /* choose random color based on the weights*/;
} while(/*it satisfies the condition, that it is not 3rd same color in a row*/)
yield return nextColor;
count--;
}
}
答案 1 :(得分:1)
大声思考,我会尝试
现在,您可以简单地在[0..max_number_of_valid_combinations] 1 之间生成均匀分布的随机“魔术”数字。对于每个选定的幻数,您可以打印生成的有效组合。
如果您有兴趣,我可能会找一些时间试试这个。 (我更喜欢在C ++ / Python中这样做,但是C#应该是可能的(.Net 4.0还有BigInteger calss吗?))
1 (这可能是一个巨大的数字,所以你可能会遇到某种类型的BigInteger,并生成多个随机数来达到大数。确保你理解分配算法到确保这仍然是均匀分布的......
2 有大量的组合数据可以得到合适的乘数,以便在生成过程中找到特定点的可能“尾部组合”的数量。这是IMO的复杂瓶颈