Non Transitive Dice 之我探
来源:互联网 发布:java上传本地文件 编辑:程序博客网 时间:2024/04/29 05:10
NonTransitive Dice之我探
前些天在网上突然看到NonTransitiveDice,也就是非传递性骰子。它们的面值不是规则的1~6,而是可以重复,当然其面值也不只到6而已。其特性是非传递的,也即若A胜B,B胜C,则A不一定胜C,可以做到C胜A。比如下面的三个骰子:
A :2, 2, 4, 4, 9, 9
B :1, 1, 6, 6, 8, 8
C :3, 3, 5, 5, 7, 7
通过概率的计算,可以证明,A胜B的概率为20/36,B胜C的概率和C胜A的概率都是20/36。
我希望通过程序来寻找这种非传递的骰子。还是使用python比较方便,但我不使用穷举法,因为当我需要寻找多个骰子的时候,穷举法的解空间太大,所以我还是进行一定次数的随机尝试吧,当然两次运行程序得到的结果可能不同。
1
首先,我需要一个函数来生成骰子的各个面,面值是从已知的数值范围内随机选择的,所以先定义面值取值列表:
#!/usr/bin/python
#-*- coding:utf-8 -*-
#FileName : dice.py
importrandom
'''
计算非传递性骰子的胜率
'''
DiceFace= range(1, 7)
这里设定面值为1~6.随机生成面值的函数(v1.0)如下:
# GenerateDie v1.0
defGenerateDie(facenum):
'''生成骰子的各个面值,共facenum面'''
d= []
i= 0
whilei < facenum:
v= random.choice(DiceFace)
d.append(v)
i+= 1
d.sort()
returnd
从diceFace中随机选择facenum个值来生成一个骰子的面值。
2
其次,我还需要一个函数来计算骰子A对骰子B的胜率,但为了获得更全面的信息,该函数还应该返回负率及和率。函数如下:
# countLtEqGt v1.0
defcountLtEqGt(num, L):
'''计算num比L中小、等、大的个数'''
cl= 0
ce= 0
cg= 0
fort in L:
ifnum < t:
cl+= 1
elifnum == t:
ce+= 1
else:
cg+= 1
return(cl, ce, cg)
# pAB v1.0
defpAB(A, B):
'''计算骰子A对B胜率,和率及负率'''
facenum= len(A)
pF= 0
pE= 0
pW= 0
fora in A:
(cl,ce, cg) = countLtEqGt(a, B)
pF+= cl
pE+= ce
pW+= cg
return(pF, pE, pW)
由于骰子各个面出现的概率相同,所以统计面值大小的个数,就相当于统计概率。有了函数pAB,就可以掌握任意两个骰子之间的战斗情况了。
3
最后,在主函数里,尝试一定的次数,生成3个骰子,使得骰子A胜B,B胜C,C胜A,并打印各个骰子的面值以及胜率。函数如下:
#主函数v1.0
if__name__ == '__main__':
N= 6 #骰子面数
T= N*N/2 #胜数之半
i= 0
n= 0
whilei < 100000:
dieA= GenerateDie(N)
dieB= GenerateDie(N)
dieC= GenerateDie(N)
(pFab,pEab, pWab) = pAB(dieA, dieB)
(pFbc,pEbc, pWbc) = pAB(dieB, dieC)
(pFca,pEca, pWca) = pAB(dieC, dieA)
cond1= (pWab > T) and (pWbc > T) and (pWca > T)
ifcond1:
n+= 1
print'dieA :', dieA
print'dieB :', dieB
print'dieC :', dieC
print'num %d : pWab = %d, pWbc = %d, pWca = %d' % (n, pWab, pWbc, pWca)
print''
i+= 1
print'find %d pairs' % n
在此寻找6面骰子,尝试100000次,先生成3个骰子,然后计算其相互之间的胜率,如果相互胜率都过半,则满足条件,成为非传递骰子,将其打印输出,并统计总共找到多少对骰子。
前面已经确定面值空间为1~6,运行该程序。等待...居然没有找到这样的骰子!即使把尝试次数增加10倍也无法找到。
把面值空间增加2倍,即取
DiceFace= range(1, 13)
再运行,找出了5对:
dieA: [1, 7, 9, 10, 10, 11]
dieB: [6, 6, 7, 7, 7, 12]
dieC: [1, 2, 4, 11, 12, 12]
num1 : pWab = 22, pWbc = 19, pWca = 19
dieA: [2, 3, 4, 5, 6, 12]
dieB: [1, 1, 3, 10, 11, 11]
dieC: [2, 6, 7, 7, 9, 9]
num2 : pWab = 19, pWbc = 19, pWca = 24
dieA: [4, 6, 6, 6, 6, 12]
dieB: [3, 3, 5, 6, 11, 12]
dieC: [1, 2, 7, 8, 8, 10]
num3 : pWab = 19, pWbc = 20, pWca = 20
dieA: [5, 5, 5, 5, 7, 12]
dieB: [2, 3, 4, 10, 11, 11]
dieC: [2, 4, 7, 8, 8, 10]
num4 : pWab = 21, pWbc = 19, pWca = 19
dieA: [2, 2, 3, 3, 12, 12]
dieB: [1, 1, 7, 9, 10, 11]
dieC: [2, 5, 6, 6, 7, 12]
num5 : pWab = 20, pWbc = 19, pWca = 20
4
观察一下文章开头给出的3个骰子,发现B里不含有A的面值,C里不含有B的面值,当然,A里也不含有B的面值。所以我们修改一个生成骰子的函数,加入排斥表,即生成的面值不能包含在该排斥表中:
# GenerateDie v1.1
defGenerateDie(facenum, exclude = []):
'''生成骰子的各个面值,共facenum面'''
d= []
i= 0
whilei < facenum:
v= random.choice(DiceFace)
#如果该面值包含在排斥表中,则丢弃
ifv in exclude:
continue
d.append(v)
i+= 1
d.sort()
returnd
然后在主函数中把生成骰子的语句加入排斥表,函数如下:
dieA= GenerateDie(N)
dieB= GenerateDie(N, dieA)
dieC= GenerateDie(N, dieA+dieB)
如此一来,B中不含有A的面值,C中不含有A和B中的面值,把面值空间还原成1~6,运行程序。
等到天荒地老,都没有结果,再把尝试次数降低10倍,仍然没有结果。突然想到面值只有6个,在生成前面2个骰子之后,可能排斥列表就已经包含全部的6个值了,导致骰子C永远无法生成。有什么好的办法呢?
5
先别管上面那个问题了,再改进一下生成骰子的函数。再仔细观察文章开头给出的3个骰子,发现每个骰子的面值都可重复。为获得重复面值的骰子,这里再随机选择0和1,如果选择1则重复,否则不重复。函数如下:
# GenerateDie v1.2
defGenerateDie(facenum, exclude = []):
'''生成骰子的各个面值,共facenum面'''
d= []
i= 0
whilei < facenum:
v= random.choice(DiceFace)
#如果该面值包含在排斥表中,则丢弃
ifv in exclude:
continue
d.append(v)
#以50%的概率决定是否重复该面值
j= random.choice([0,1])
ifj==1 and len(d) < facenum:
d.append(v)
i+= 2
else:
i+= 1
d.sort()
returnd
再运行程序,发现程序轻松的在10000次尝试中找到30多对骰子。列举几个如下:
dieA: [1, 3, 9, 9, 9, 9]
dieB: [2, 5, 5, 7, 8, 8]
dieC: [4, 4, 4, 4, 10, 12]
num1 : pWab = 25, pWbc = 20, pWca = 20
dieA: [3, 3, 6, 8, 8, 12]
dieB: [2, 4, 5, 5, 11, 11]
dieC: [1, 1, 9, 10, 10, 10]
num2 : pWab = 20, pWbc = 20, pWca = 20
dieA: [3, 3, 3, 5, 9, 9]
dieB: [2, 2, 7, 7, 8, 8]
dieC: [1, 1, 4, 6, 10, 10]
num3 : pWab = 20, pWbc = 20, pWca = 19
如果把面值空间还原成1~6,仍然没有解,设置成1~9,同时把生成骰子的语句改成如下:
dieA= GenerateDie(N)
dieB= GenerateDie(N, dieA)
dieC= GenerateDie(N, dieB)
则可以在10000次尝试中找到7对如下:
dieA: [3, 4, 5, 5, 9, 9]
dieB: [1, 1, 8, 8, 8, 8]
dieC: [6, 6, 6, 7, 7, 9]
num1 : pWab = 20, pWbc = 20, pWca = 24
dieA: [2, 2, 3, 3, 8, 8]
dieB: [1, 1, 6, 6, 6, 6]
dieC: [3, 3, 4, 4, 5, 8]
num2 : pWab = 20, pWbc = 20, pWca = 20
dieA: [2, 3, 4, 5, 9, 9]
dieB: [1, 1, 7, 7, 7, 7]
dieC: [5, 5, 5, 5, 5, 9]
num3 : pWab = 20, pWbc = 20, pWca = 19
dieA: [4, 6, 6, 6, 6, 9]
dieB: [1, 1, 3, 8, 8, 8]
dieC: [2, 4, 7, 7, 7, 7]
num4 : pWab = 21, pWbc = 19, pWca = 20
dieA: [2, 6, 6, 6, 6, 6]
dieB: [3, 3, 4, 5, 8, 9]
dieC: [2, 2, 6, 7, 7, 7]
num5 : pWab = 20, pWbc = 20, pWca = 19
dieA: [3, 3, 4, 4, 9, 9]
dieB: [1, 1, 7, 7, 7, 7]
dieC: [5, 5, 6, 6, 6, 6]
num6 : pWab = 20, pWbc = 24, pWca = 24
dieA: [2, 2, 7, 7, 7, 7]
dieB: [3, 3, 5, 6, 6, 9]
dieC: [2, 2, 4, 8, 8, 8]
num7 : pWab = 20, pWbc = 19, pWca = 20
6
现在我想找5个骰子,每个骰子都是6个面,如果全部不重复,则需要30个面值,所以面值空间设置成1~30,即DiceFace= range(1, 31),尝试100000次。当然,骰子生成函数使用v1.2.
我不只是要得到简单的循环胜的骰子,而是要得到五行相克的骰子,即A胜B,B胜C,C胜D,D胜E,最后E胜A,同时还要保证C胜A,D胜B,E胜C,A胜D,B胜E,见下图
所以主函数不但要计算A胜B,B胜C,C胜D,D胜E和E胜A的概率,还要计算C胜A,D胜B,E胜C,A胜D,B胜E的概率,两个条件都满足才输出。函数如下:
#主函数v1.1
if__name__ == '__main__':
N= 6
T= N*N/2
i= 0
n= 0
whilei < 100000:
dieA= GenerateDie(N)
dieB= GenerateDie(N, dieA)
dieC= GenerateDie(N, dieA+dieB)
dieD= GenerateDie(N, dieA+dieB+dieC)
dieE= GenerateDie(N, dieA+dieB+dieC+dieD)
(pFab,pEab, pWab) = pAB(dieA, dieB)
(pFbc,pEbc, pWbc) = pAB(dieB, dieC)
(pFcd,pEcd, pWcd) = pAB(dieC, dieD)
(pFde,pEde, pWde) = pAB(dieD, dieE)
(pFea,pEea, pWea) = pAB(dieE, dieA)
(pFca,pEca, pWca) = pAB(dieC, dieA)
(pFdb,pEdb, pWdb) = pAB(dieD, dieB)
(pFec,pEec, pWec) = pAB(dieE, dieC)
(pFad,pEad, pWad) = pAB(dieA, dieD)
(pFbe,pEbe, pWbe) = pAB(dieB, dieE)
cond1= (pWab > T) and (pWbc > T) and (pWcd > T) and (pWde > T)and (pWea > T);
cond2= (pWca > T) and (pWdb > T) and (pWec > T) and (pWad > T)and (pWbe > T);
ifcond1 and cond2:
n+= 1
print'dieA :', dieA
print'dieB :', dieB
print'dieC :', dieC
print'dieD :', dieD
print'dieE :', dieE
print'num %d : pWab = %d, pWbc = %d, pWcd = %d, pWde = %d, pWea = %d' %(n, pWab, pWbc, pWcd, pWde, pWea)
print'num %d : pWca = %d, pWdb = %d, pWec = %d, pWad = %d, pWbe = %d' %(n, pWca, pWdb, pWec, pWad, pWbe)
print''
i+= 1
print'find %d pairs' % n
运行程序,没有找到,增加尝试次数到10倍也无法找到,将排斥列表改为如下:
dieA= GenerateDie(N)
dieB= GenerateDie(N, dieA)
dieC= GenerateDie(N, dieB)
dieD= GenerateDie(N, dieC)
dieE= GenerateDie(N, dieD+dieA)
也无法找到。
我怒了,把面值空间改为1~99,即DiceFace= range(1,100)。修改骰子生成函数为v1.3,即单个面值按照66.7%的概率重复3次,同时把尝试次数设为无穷大。完整的程序如下:
#!/usr/bin/python
#-*- coding:utf-8 -*-
#FileName : dice.py
importrandom
'''
计算非传递性骰子的胜率
'''
DiceFace= range(1, 100)
# GenerateDie v1.3
defGenerateDie(facenum, exclude = []):
'''生成骰子的各个面值,共facenum面'''
d= []
i= 0
whilei < facenum:
v= random.choice(DiceFace)
#如果该面值包含在排斥表中,则丢弃
ifv in exclude:
continue
d.append(v)
i+= 1
#以66.7%的概率决定是否重复该面值
j= random.choice([0, 1, 2])
ifj>=1 and i < facenum:
d.append(v)
i+= 1
ifi < facenum:
d.append(v)
i+= 1
d.sort()
returnd
defcountLtEqGt(num, L):
'''计算num比L中小、等、大的个数'''
cl= 0
ce= 0
cg= 0
fort in L:
ifnum < t:
cl+= 1
elifnum == t:
ce+= 1
else:
cg+= 1
return(cl, ce, cg)
defpAB(A, B):
'''计算骰子A对B胜率,和率及负率'''
facenum= len(A)
pF= 0
pE= 0
pW= 0
fora in A:
(cl,ce, cg) = countLtEqGt(a, B)
pF+= cl
pE+= ce
pW+= cg
return(pF, pE, pW)
if__name__ == '__main__':
N= 6
T= N*N/2
i= 0
n= 0
whileTrue:#i < 1000000:#尝试无穷次
dieA= GenerateDie(N)
dieB= GenerateDie(N, dieA)
dieC= GenerateDie(N, dieB)
dieD= GenerateDie(N, dieC)
dieE= GenerateDie(N, dieD+dieA)
(pFab,pEab, pWab) = pAB(dieA, dieB)
(pFbc,pEbc, pWbc) = pAB(dieB, dieC)
(pFcd,pEcd, pWcd) = pAB(dieC, dieD)
(pFde,pEde, pWde) = pAB(dieD, dieE)
(pFea,pEea, pWea) = pAB(dieE, dieA)
(pFca,pEca, pWca) = pAB(dieC, dieA)
(pFdb,pEdb, pWdb) = pAB(dieD, dieB)
(pFec,pEec, pWec) = pAB(dieE, dieC)
(pFad,pEad, pWad) = pAB(dieA, dieD)
(pFbe,pEbe, pWbe) = pAB(dieB, dieE)
cond1= (pWab > T) and (pWbc > T) and (pWcd > T) and (pWde > T)and (pWea > T);
cond2= (pWca > T) and (pWdb > T) and (pWec > T) and (pWad > T)and (pWbe > T);
ifcond1 and cond2:
n+= 1
print'dieA :', dieA
print'dieB :', dieB
print'dieC :', dieC
print'dieD :', dieD
print'dieE :', dieE
print'num %d : pWab = %d, pWbc = %d, pWcd = %d, pWde = %d, pWea = %d' %(n, pWab, pWbc, pWcd, pWde, pWea)
print'num %d : pWca = %d, pWdb = %d, pWec = %d, pWad = %d, pWbe = %d' %(n, pWca, pWdb, pWec, pWad, pWbe)
print''
#i+= 1
print'find %d pairs' % n
注意,骰子生成时使用的排斥列表只是上一个骰子,而不是前面全部的骰子。程序经过一个晚上的运行计算,得到几个结果:
dieA: [6, 37, 37, 37, 78, 78]
dieB: [22, 22, 22, 47, 63, 83]
dieC: [4, 45, 45, 45, 60, 60]
dieD: [30, 36, 36, 36, 93, 93]
dieE: [15, 15, 15, 64, 83, 91]
num1 : pWab = 19, pWbc = 19, pWcd = 20, pWde = 24, pWea = 19
num1 : pWca = 20, pWdb = 24, pWec = 21, pWad = 20, pWbe = 19
dieA: [22, 22, 29, 35, 85, 94]
dieB: [15, 20, 79, 79, 79, 83]
dieC: [42, 45, 45, 45, 72, 85]
dieD: [20, 20, 20, 81, 81, 90]
dieE: [4, 50, 50, 50, 60, 60]
num2 : pWab = 20, pWbc = 20, pWcd = 20, pWde = 21, pWea = 20
num2 : pWca = 24, pWdb = 19, pWec = 20, pWad = 23, pWbe = 26
dieA: [24, 24, 44, 44, 44, 95]
dieB: [4, 35, 35, 35, 59, 93]
dieC: [25, 25, 25, 57, 57, 57]
dieD: [3, 41, 41, 41, 51, 53]
dieE: [28, 28, 28, 46, 46, 96]
num3 : pWab = 20, pWbc = 21, pWcd = 21, pWde = 19, pWea = 22
num3 : pWca = 21, pWdb = 20, pWec = 21, pWad = 20, pWbe = 19
dieA: [30, 30, 30, 46, 91, 91]
dieB: [7, 7, 40, 80, 80, 80]
dieC: [31, 37, 37, 37, 65, 69]
dieD: [25, 25, 25, 60, 84, 84]
dieE: [23, 50, 50, 50, 55, 58]
num4 : pWab = 21, pWbc = 22, pWcd = 20, pWde = 21, pWea = 20
num4 : pWca = 20, pWdb = 21, pWec = 20, pWad = 24, pWbe = 19
dieA: [48, 48, 56, 56, 56, 83]
dieB: [18, 20, 47, 81, 81, 81]
dieC: [39, 39, 58, 59, 59, 59]
dieD: [32, 32, 32, 41, 87, 94]
dieE: [12, 29, 64, 70, 70, 70]
num5 : pWab = 21, pWbc = 20, pWcd = 22, pWde = 20, pWea = 20
num5 : pWca = 20, pWdb = 20, pWec = 24, pWad = 24, pWbe = 22
dieA: [26, 28, 28, 28, 61, 61]
dieB: [2, 8, 49, 49, 49, 57]
dieC: [23, 30, 30, 30, 41, 86]
dieD: [12, 12, 12, 47, 92, 92]
dieE: [3, 32, 32, 45, 45, 45]
num6 : pWab = 20, pWbc = 20, pWcd = 19, pWde = 21, pWea = 20
num6 : pWca = 22, pWdb = 20, pWec = 23, pWad = 20, pWbe = 25
dieA: [24, 24, 24, 48, 91, 91]
dieB: [1, 16, 76, 77, 77, 77]
dieC: [38, 38, 60, 60, 60, 94]
dieD: [19, 19, 19, 79, 79, 79]
dieE: [15, 62, 63, 63, 63, 66]
num7 : pWab = 20, pWbc = 20, pWcd = 21, pWde = 21, pWea = 20
num7 : pWca = 24, pWdb = 24, pWec = 25, pWad = 24, pWbe = 25
dieA: [14, 36, 59, 62, 62, 62]
dieB: [22, 24, 24, 24, 95, 95]
dieC: [1, 10, 70, 70, 70, 88]
dieD: [29, 29, 39, 39, 39, 90]
dieE: [17, 17, 17, 75, 75, 75]
num8 : pWab = 20, pWbc = 20, pWcd = 20, pWde = 21, pWea = 21
num8 : pWca = 24, pWdb = 24, pWec = 21, pWad = 22, pWbe = 24
以上就是五行骰子。
7
本文是我在网站http://www.guokr.com/blog/90573/上看到《非传递性骰子:一个模型及猜想》文章,受到启发而作的。似乎它有一个结论:欲使胜率最大,则面值一定会重复。所以完全可能通过重新设计骰子生成函数GenerateDie来获得特殊骰子,这或许就是本文的建模了。
现在修改GenerateDie为v1.4,即得到一个面值后,一定重复它。
DiceFace= range(1, 10)
#GenerateDie v1.4
defGenerateDie(facenum, exclude = []):
'''生成骰子的各个面值,共facenum面'''
d= []
i= 0
whilei < facenum:
v= random.choice(DiceFace)
#如果该面值包含在排斥表中,则丢弃
ifv in exclude:
continue
d.append(v)
i+= 1
#重复该面值
ifi < facenum:
d.append(v)
i+= 1
d.sort()
returnd
此时仍然使用主函数生成3个骰子,函数为:
if__name__ == '__main__':
N= 6 #骰子面数
T= N*N/2 #胜数之半
i= 0
n= 0
whilei < 10000:
dieA= GenerateDie(N)
dieB= GenerateDie(N, dieA)
dieC= GenerateDie(N, dieB+dieA)
(pFab,pEab, pWab) = pAB(dieA, dieB)
(pFbc,pEbc, pWbc) = pAB(dieB, dieC)
(pFca,pEca, pWca) = pAB(dieC, dieA)
cond1= (pWab > T) and (pWbc > T) and (pWca > T)
ifcond1:
n+= 1
print'dieA :', dieA
print'dieB :', dieB
print'dieC :', dieC
print'num %d : pWab = %d, pWbc = %d, pWca = %d' % (n, pWab, pWbc, pWca)
print''
i+= 1
print'find %d pairs' % n
程序可以轻松找出一大堆骰子来。其中有一对是这样的:
dieA: [2, 2, 4, 4, 9, 9]
dieB: [1, 1, 7, 7, 8, 8]
dieC: [3, 3, 5, 5, 6, 6]
num28 : pWab = 20, pWbc = 24, pWca = 20
文章开头给出的骰子是:
A :2, 2, 4, 4, 9, 9
B :1, 1, 6, 6, 8, 8
C :3, 3, 5, 5, 7, 7
其相互胜率为20/36
- Non Transitive Dice 之我探
- Dice
- 网络赛之Dice (BFS,hdu5012)
- BFS + 剪枝 之 hdu 5012 Dice
- 解题报告 之 SOJ4429 Frog's Dice
- maven之Transitive dependencies(默认树的先序遍历算法处理依赖冲突)
- § Transitive & Intransitive Verb
- couting transitive relation
- maven transitive dependency
- Transitive Closure算法笔记
- Gradle transitive = true
- 【我的Android进阶之旅】解决strings.xml格式化占位符错误: Multiple substitutions specified in non-positional format
- 【我的Android进阶之旅】Android 源代码中的Java代码中//$NON-NLS-1$ 注释是什么意思?
- denoising 之 Non local means
- hadoop之non dfs used
- Non
- [Gradle中文教程系列]-跟我学Gradle-5.3:依赖-管理依赖的版本(传递(transitive)\排除(exclude)\强制(force)\动态版本(+))
- [Gradle中文教程系列]-跟我学Gradle-5.3:依赖-管理依赖的版本(传递(transitive)\排除(exclude)\强制(force)\动态版本(+))
- CDBVariant 二进制数据读取
- 三维GIS软件十九重唱
- Android消息机制
- mac 强制退出
- 概率随机问题
- Non Transitive Dice 之我探
- Java中判断String不为空的问题
- Android的Message机制(简单小结)
- 几款android的游戏引擎
- windows路径操作API函数
- 天易31----CMMI(软件能力成熟度模型集成)
- 关于ORA_32004错误的解决
- nyoj-219-An problem about date
- 打印螺旋序列