博弈游戏:两个玩家在博弈游戏中的每个步骤都是有一个目的,可以分成两种不同的实现方式
1.让自己的最终得分更高 2.让对手的最终得分更低
在这道题中,对于一个数组 arr[1,5,233,7],玩家可以每次从该数组的首尾选择一个数,然后比较最终的结果,不能下意识的去让其中一个玩家想方设法的赢,这两个玩家都是"聪明"的。我们先假设玩家一的得分为Index1,玩家二的得分为Index2。玩家一先进行选择,那么玩家一有两种选择,可以选择1或者7
上图是两种不同的选择方式,蓝色是玩家一,橙色是玩家二。可以看出玩家一选完之后从首尾选完之后又变成了玩家一从剩余数组元素的首尾去选择元素使得自己的得分最大,就是一个子问题,我们可以考虑用递归的思想去完成这个问题。我们可以分别计算分数或者是每轮中计算差值。
1算一个玩家的分数.如上面的图中,最上面的一轮 选择1最后的到的分数和选择7最后的到的分数的最大值 max{function(1),function(7)},function为递归函数。 设 left=0,right=arr.length。 我们可以用第二轮玩家二选择后取min值,因为玩家二总是也想赢的,所以他会阻碍玩家一的胜利所以让玩家一的总分数尽可能的偏小。
pre=nums[left]+fmin(getgoal(nums,left+2,right),getgoal(nums,left+1,right-1));
before=nums[right]+fmin(getgoal(nums,left+1,right-1),getgoal(nums,left,right-2));
pre为选择第一个,before为选择第二个,返回最大值即可。arr[1,5,233,7] 1.玩家一选一之后1之后 arr[5,233,7] 玩家二选择的是 5 那么玩家一就在arr[233,7]里面选,玩家二选择的是 7 玩家一就在arr[5,233]里面选择。那么返回的就是玩家二选择后的最小值。
1 5 233 7
left right
如果只剩下两个元素,那么就把左边的给left,右边的给right,意思是玩家一选完之后玩家二只能选择最后剩下的一个。只剩一个只就直接返回值
这样我们就能计算出玩家一的分数,用总的分数减去玩家一的分数就能得到玩家二的分如果>0我们就返回true 否则false。这样会有很多重复的运算,我们可以每轮中只计算两个玩家的差值。
2 计算差值.也要用一个pre和一个before的值分别计算选择前面和后面的最终的值。并且使用一个flag值来判断是哪个玩家,让玩家二的值为负。arr[1,5,233,7]
玩家一选择了之后,认为玩家二选择的值是负数这样能得到一个差值,返回这个差值的最大值,如果大于0那么玩家一胜利。玩家二阶段,判断最大值的时候此时返回的最大值并不是数学意义上的最大值,而是让玩家一得分最小的一个值,例如 递归返回到玩家二阶段的pre的值和before的值分别为 -8 3 因为我们让pre*falg before*flag变为相反数然后会取得最大值8,然后再让结果res*flag就变回了之前的值,这样就能在玩家二选出差值的最小值。
这样依旧会有重复的计算使用我们稍加改进代码,用一个哈希表hash[][]储存下表left right阶段的返回值。遇到重复的我们直接调用哈希表返回给我们相应的值。