一道ACM博弈题,交互比较麻烦
第一关:巴什博弈
两人取石子,总共n个,每次拿 1 - m 个,问先手胜还是负,胜的话输出每一步策略
第二关:威佐夫博弈
两人取石子,总共两堆,可以从两堆里拿相同的数目,也可以从一堆中拿任意多个,问先手胜还是负,胜的话输出每一步策略
先上代码吧
import math ''' for k in xrange(1,10): a = int(k * (sq5 + 1) / 2) b = a + k print k,a,b 1 1 2 2 3 5 3 4 7 4 6 10 5 8 13 6 9 15 7 11 18 8 12 20 9 14 23 ''' def weizuofu(a,b): if (a==b): return a,2 elif a==0: return b,1 elif b==0: return a,0 swp = 0 if a>b: a,b = b,a swp = 1 sq5 = math.sqrt(5.0) k = b - a ak = int(k * (sq5 + 1) / 2) bk = ak + k print a,b,k,ak,bk if (ak == a) and (bk == b): return -1,-1 elif (a > ak) and (b > bk): return b - bk,2 else: for i in range(b): newa = a newb = b - i if newa > newb: newa,newb = newb,newa newk = newb - newa sa = int(newk * (sq5 + 1) / 2) sb = sa + newk if (sa == newa) and (sb == newb): return i,1^swp break #print weizuofu(1,2) #print weizuofu(2,2) #print weizuofu(2,3) #print weizuofu(4,87) #print weizuofu(2,6) #print weizuofu(3,10) #print weizuofu(50,100) #print weizuofu(74,83) #a = 19127 #b = 20155 a = 1581 b = 397 T = 0 while 1: T += 1 print '<',T,'>', x,y = weizuofu(a,b) #print x,y if x == 100 and y == 100: print 'WIN' break elif x == -1 and y == -1: print 'GG' break else: if y==1: b -= x if a>b: a,b = b,a print 'sub b' elif y==0: a -= x print 'sub a' else: a -= x b -= x print 'sub a b'
威佐夫博弈分析及结论:https://blog.csdn.net/qq_34374664/article/details/52814983
首先判断是不是先手必败态:k = abs(a - b),然后根据公式算ak和bk,对应相等就是必败态,否则:
如果a和b都比ak和bk要大,说明先手策略是:在两个石堆里拿相同数目min(a,b) - min(ak,bk)个
不满足,就需要从大的里枚举减掉多少个,可以让后手满足必败态
举例子:
(2,3) -> (1,2)
(3,4) -> (3,2)
(15,23) -> (15,9)
(12,19) -> (11,18)
第三关:NIM博弈
两人取石子,n堆,每堆xi个,每次可以从任意一堆拿任意多个,问先手胜负态和方案
NIM博弈:https://blog.csdn.net/u012925008/article/details/45476629
小学奥数结论:都异或起来为0,先手必败;否则,先手在某一堆中拿掉异或结果,后手进入先手必败态
最后代码:
http://bendawang.site/2018/05/28/SUCTF-2018-%E9%83%A8%E5%88%86%E9%A2%98%E8%A7%A3/n