我有一个类似的问题:

我们有20个球,每个球都是唯一的,用一个从1到20的数字来标识.从1到5的球是黄色的,从6到10是绿色的,从10到15是红色的,从16到20是蓝色的.找到一种方法来随机洗牌球,同时遵守约束:"两个连续的球不能有相同的 colored颜色 ".

示例:

input/output example

我已经考虑了两种我不满意的方法,我正在寻找更好的方法

  1. 随机画一个球,然后在所有其他 colored颜色 与前一个不同的球中随机画一个球,以此类推.

问题:在不可能完成绘图的情况下,例如,如果只有相同 colored颜色 的剩余球,我们可能会摔倒.

  1. 将球分成4组,每组5个球(每种 colored颜色 1个),通过随机抽取每种 colored颜色 的一个球,形成另外5组4个球.重新组合这5组以符合标准(最后一组的第一个球被置换,直到符合标准).

问题:有些组合从来不画,例如红、黄、红、黄……绿色,蓝色,绿色,蓝色.

Edit:

以下是Unlikus解决方案的实现.非常感谢他.

import enum
import random

Color = enum.Enum('Color', ['RED', 'GREEN', 'BLUE', "YELLOW"])

NB_PERMUTATION = {
        (Color.RED, 1, 0, 0, 0): 1,
        (Color.GREEN, 0, 1, 0, 0): 1,
        (Color.BLUE, 0, 0, 1, 0): 1,
        (Color.YELLOW, 0, 0, 0, 1): 1,
        (Color.RED, 0, 0, 0, 0): 0,
        (Color.GREEN, 0, 0, 0, 0): 0,
        (Color.BLUE, 0, 0, 0, 0): 0,
        (Color.YELLOW, 0, 0, 0, 0): 0,
    }

def compute_nb_permutations(*args):
    try:
        return NB_PERMUTATION[args]
    except KeyError:
        second_colors = {1, 2, 3, 4} - {args[0].value}
        nb_ball = [args[1], args[2], args[3], args[4]]
        nb_ball[args[0].value - 1] -= 1
        result = NB_PERMUTATION[args] = sum(
            compute_nb_permutations(Color(c), *nb_ball) for c in second_colors if nb_ball[c - 1] > 0
        )
        return result

def arrange_color():
    colors = {*Color}
    nb_ball = [5,5,5,5]

    # choose uniformly among colors for the first ball
    results = [random.choices(list(colors))[0]]
    nb_ball[results[-1].value - 1] -= 1

    while nb_ball != [0,0,0,0]:
        candidates = list(colors - {results[-1]})
        weights = [compute_nb_permutations(c, *nb_ball) for c in candidates]
        results.append(random.choices(candidates, weights=weights)[0])
        nb_ball[results[-1].value - 1] -= 1

    return results

def draw():
    numbers = {
        Color.RED: list(range(1,6)),
        Color.GREEN: list(range(6, 11)),
        Color.BLUE: list(range(11, 16)),
        Color.YELLOW: list(range(16, 21)),
    }
    for v in numbers.values():
        random.shuffle(v)

    return {numbers[c].pop(): c.name for c in arrange_color()}

推荐答案

在这种规模下,你可以进行拒收抽样.平均而言,只需不到100次try 就可以找到有效的订单.

import itertools
import random


deck = range(1, 21)


def color(i):
    return "RGBY"[(i - 1) // 5]


shuffle_count = 0


def sample():
    global shuffle_count
    order = list(deck)
    while True:
        shuffle_count += 1
        random.shuffle(order)
        if all(color(i) != color(j) for (i, j) in itertools.pairwise(order)):
            return order


n = 1000
for j in range(n):
    sample()
print(shuffle_count / n)
print(sample())

示例输出:

87.227
[3, 10, 15, 4, 18, 5, 11, 17, 7, 19, 8, 2, 14, 20, 1, 12, 9, 13, 16, 6]

Python相关问答推荐

Python panda拆分列保持连续多行

如何用symy更新分段函数

跟踪我已从数组中 Select 的样本的最有效方法

用gekko解决的ADE方程系统突然不再工作,错误消息异常:@错误:模型文件未找到.& &

将HLS纳入媒体包

如何使用SubProcess/Shell从Python脚本中调用具有几个带有html标签的参数的Perl脚本?

使用scipy. optimate.least_squares()用可变数量的参数匹配两条曲线

分组数据并删除重复数据

如何让剧作家等待Python中出现特定cookie(然后返回它)?

对整个 pyramid 进行分组与对 pyramid 列子集进行分组

如何根据参数推断对象的返回类型?

沿着数组中的轴计算真实条目

Pandas:将多级列名改为一级

关于Python异步编程的问题和使用await/await def关键字

下三角形掩码与seaborn clustermap bug

以逻辑方式获取自己的pyproject.toml依赖项

如何使用使用来自其他列的值的公式更新一个rabrame列?

Beautifulsoup:遍历一个列表,从a到z,并解析数据,以便将其存储在pdf中.

合并相似列表

如何关联来自两个Pandas DataFrame列的列表项?