[蓝桥杯] 高僧斗法 python3满分题解
前言
本人小白一枚,这是我第一次接触博弈算法。高僧斗法就是一个经典的博弈算法实例。特别来记录一下:
这个题目是博弈算法中的nim模型,有关于nim模型,详见百度百科-nim模型
,看完这个后我们知道了什么是p-position,n-position,以及通过异或操作判断p-position的方法
一、解题思路
我们对于这个题目,可以看作是另外一种模式的石子堆游戏。如下:
将小和尚按照两两分组,如果是奇数,则最后一个小和尚就不参与分组。则第一组中(A和B)因为A可以移动的步数为5-1-1=3,我们就看作这堆石子还剩三个。同理第二组还剩1个。此时我们将3和1进行异或,如果为0,则此时s=0,表示为P-position,输出-1。如果s!=0,我们进行小组的循环,得到除了某个小组之外的其它异或值target,让每一个小组想办法变成这个target,因为变成两个target之后就会让异或为0,这样就一定会取胜。在遍历的过程中,记录最小的符合结果的值
二、代码
class Solution:
def monkFighting(self,nums):
n=len(nums)
min_pos=-1
min_move=nums[-1]
groups=[0]*(n//2)
temp=0
for i in range(0,n-1,2):
groups[temp]=nums[i+1]-nums[i]-1
temp+=1
s=0
for j in range(temp):
s^=groups[j]
if s==0:
print(-1)
return
for i in range(temp):
s=0
for j in range(temp):
if i!=j:
s^=groups[j]
if s<groups[i]:
if groups[i]-s<min_move:
min_pos=i*2
min_move=groups[i]-s
elif s>groups[i]:
if s-groups[i]<min_move and nums[i*2+2]-nums[i*2+1]-1>s-groups[i]:
min_pos=i*2+1
min_move=s-groups[i]
print(nums[min_pos],nums[min_pos]+min_move)
if __name__ == "__main__":
solution = Solution
temp=map(int,input().split())
nums=[num for num in temp]
solution.monkFighting(solution,nums)
总结
这个题目,我们应该学会博弈算法的基本思想