例如,我想洗牌4副牌,并确保:
任何连续的4张牌都不会来自同一副牌。
当然,我可以先洗牌,然后过滤掉坏的排列,但如果限制很强(例如,任何连续的两张牌都不会来自同一副牌),就会有太多的失败。
如果我不介意有点不偏袒(当然偏袒越少越好),我该怎么办?
编辑:澄清
是的,我希望尽可能一致地从所有完全洗牌中选择,以便应用此附加条件。

最佳答案

我将处理如下:
首先你可以洗牌每4组(使用FYK算法)
然后生成一个4个分区(*i define partition below)的52张卡(共4张卡),每个分区集中的元素不超过3个:
例如:

(1,3,0,3,2,0,1) would be a partition of 10 with this constraint
(1,1,1,1,1,1,1,1,1,1) would be a partition of 10 too with this constraint

然后根据这些隔板混合4层甲板。
例如,如果您有:
(3,2,1)
(2,2,2)

你先拿第一层的3,然后拿第二层的2,然后拿第一层的2,再拿第二层的2,然后拿第一层的1,然后拿第二层的2。(好吗?)
所有分区都无效,因此需要再添加一个约束:
例如,使用此方法:
(1,2,1,1,1,1,1,1)
(3,3,3)

最后将有4个元素的甲板1结束。
所以最后一个分区必须满足一个约束,我编写了一个小python程序来生成这些分区。
from random import randint,choice

def randomPartition(maxlength=float('inf'),N=52):
    '''
    the max length is the last constraint in my expanation:
      you dont want l[maxlength:len(l)]) to be more than 3
 in this case we are going to randomly add +1 to all element in the list that are less than 3

    N is the number of element in the partition
     '''
    l=[] # it's your result partition
    while(sum(l)<N ):
        if (len(l)>maxlength and sum(l[maxlength:len(l)])>=3): #in the case something goes wrong
            availableRange=[i for i in range(len(l)) if l[i]<3] #create the list of available elements to which you can add one
            while(sum(l)<N):
                temp=choice(availableRange) #randomly pick element in this list
                l[temp]+=1
                availableRange=[i for i in range(len(l)) if l[i]<3] #actualize the list
                if availableRange==[]: #if this list gets empty your program cannot find a solution
                    print "NO SOLUTION"
                    break
            break
        else:
            temp=randint(0,min(N-sum(l),3)) # If everything goes well just add the next  element in the list until you get a sum of N=52
            l.append(temp)
    return l

现在您可以生成4个分区并根据这些分区混合甲板:
def generate4Partitions():
    l1=randomPartition();
    l2=randomPartition();
    l3=randomPartition();
    m=max(len(l1),len(l2),len(l3))
    l4=randomPartition(m);
    return l1,l2,l3,l4

根据其定义,这4个分区始终是可接受的。
注:
可能会有更多不可受理的情况,例如:
(3,0,0,3)
(0,3,3,0)

我想这段代码需要稍加修改以考虑更多的约束。
但是很容易删除不需要的零,比如:
(3,0,3)
(0,3,3,0)

希望这是可以理解的

关于c# - 如何在有限制的情况下将Fisher-Yates-Knuth应用于洗牌?还是有其他有效的方法?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7822299/

10-11 05:05