规则是这样的
我相信这会给出正确的甲板尺寸
import itertools
# define base deck
base_deck = [2, 3, 4, 5, 6, 7, 8, 9, 10]
# define deck sizes
deck_a_size = 2
deck_b_size = 3
# create decks
deck_a_cards = list(itertools.chain.from_iterable(itertools.repeat(base_deck, deck_a_size)))
deck_a_cards.extend(floater)
print(deck_a_cards)
deck_b_cards = list(itertools.chain.from_iterable(itertools.repeat(base_deck, deck_b_size)))
deck_a_cards.extend(floater)
print(deck_b_cards)
但是,我不确定这是否会计算出正确的概率
对于和a,b
import itertools
# define base deck
base_deck = [2, 3, 4, 5, 6, 7, 8, 9, 10]
# define deck sizes
deck_a_size = 1
deck_b_size = 3
# create decks
deck_a_cards = list(itertools.chain.from_iterable(itertools.repeat(base_deck, deck_a_size)))
deck_a_cards.extend(floater)
print(deck_a_cards)
deck_b_cards = list(itertools.chain.from_iterable(itertools.repeat(base_deck, deck_b_size)))
deck_b_cards.extend(floater)
print(deck_b_cards)
deck_a_success = 0
deck_b_success = 0
total_combinations = 0
for i in itertools.product(deck_a_cards, repeat=deck_a_size):
for j in itertools.product(deck_b_cards, repeat=deck_b_size):
deck_a_sum = sum(i)
deck_b_sum = sum(j)
if deck_a_sum > deck_b_sum:
deck_a_success += 1
elif deck_a_sum < deck_b_sum:
deck_b_success += 1
else:
deck_b_success += 1
total_combinations += 1
deck_a_prob = deck_a_success / total_combinations
deck_b_prob = deck_b_success / total_combinations
print("Probability of success with {} cards drawn:".format(deck_a_size + deck_b_size))
print("Deck A:", deck_a_prob)
print("Deck B:", deck_b_prob)
最后必须有更好的方法来做到这一点,因为这是非常糟糕的时间复杂度。
好吧,我现在也尝试过蒙特卡洛模拟
对于尺寸 2,3 和 1,3 我得到非常相似的值:
import random
base_deck = [2, 3, 4, 5, 6, 7, 8, 9, 10]
deck_a_size = 2
deck_b_size = 3
num_trials = 1000000
deck_a_wins = 0
deck_b_wins = 0
for i in range(num_trials):
deck_a_sum = sum(random.sample(base_deck, deck_a_size))
deck_b_sum = sum(random.sample(base_deck * deck_b_size, deck_b_size))
if deck_a_sum > deck_b_sum:
deck_a_wins += 1
elif deck_b_sum > deck_a_sum:
deck_b_wins += 1
deck_a_prob = deck_a_wins / num_trials
deck_b_prob = deck_b_wins / num_trials
print("Probability of success with {} cards drawn:".format(deck_a_size+deck_b_size))
print("Deck A:", deck_a_prob)
print("Deck B:", deck_b_prob)
抽到5张牌的成功概率: 甲板A:0.1316926655146557 B 层:0.8683073344853444 运行时间 6.0s
与蒙特卡洛
抽到5张牌的成功概率: 甲板A:0.121357 甲板 B:0.837629 运行时间 3.8s
你的结果似乎是正确的。
由于您的代码使用的是产品(而不是排列),我假设进行多次抽奖时,抽出的牌会在下一次抽奖之前放回牌组中。这允许通过为给定牌组大小的每个可能总和构建概率列表来简化过程。
基于这些概率,可以将一副牌中的每个可能总和与另一副牌中的总和进行比较,并产生一个结果概率,然后我们可以将其相加得到最终结果:
from itertools import product
floaters = [7,8,9,10]
baseDeck = [2, 3, 4, 5, 6, 7, 8, 9, 10]
Bs = len(baseDeck)
Fs = len(floaters)
def getSumProb(size):
prob = {n:(size+(n in floaters))/(size*Bs+Fs) for n in baseDeck}
sump = prob
for _ in range(1,size):
sump,prev = dict(),sump
for (s,ps),(n,pn) in product(prev.items(),prob.items()):
sump[s+n] = sump.get(s+n,0) + ps * pn
return sump
getSumProb
函数返回一个字典,其中可能的总和作为键,它们对应的概率作为值。
它首先计算每个单独数字的概率,同时考虑到浮动值的重复和增加的机会。然后,它将这个单独概率列表“折叠”到自身上以获得总和值(对于多次抽奖)及其各自的概率(即形成最终总和的概率乘积之和)。
为了计算 deckA 抽奖胜过 deckB 的概率,我们只需将 deckA 抽奖的每个可能总和的概率乘以 deckB 总和较低的概率总和。
输出:
sumsA = getSumProb(2)
sumsB = getSumProb(3)
winAprob = sum( pA*sum(pB for sB,pB in sumsB.items() if sA>sB)
for sA,pA in sumsA.items() )
winBprob = 1 - winAprob
print(winAprob) # 0.13169266551465567
print(winBprob) # 0.8683073344853444
# runs in 0.0002 sec. on my laptop
如果您需要隔离两个值相等的情况,您可以分别计算相等和的概率并从中推导出 winBprob
equalProb = sum( pA*sum(pB for sB,pB in sumsB.items() if sA==sB)
for sA,pA in sumsA.items() )
winBprob = 1 - winAprob - equalProb
print(equalProb) # 0.04061934507371048
print(winBprob) # 0.8276879894116339