暴力递归到动态规划--纸牌博弈问题
数量为N的纸牌,排成一排,每次只能取最左或最右的纸牌。现有赌怪两个,一个先手拿一个后手拿,拿到牌累加后较大者获胜,问获胜者拿取的牌加起来有多大。
解法:
1)写出递归
当纸牌长度为N时,假设赌怪1是先手,那么赌怪2就是后手;但纸牌长度为N-1时,赌怪1就变成了后手,而赌怪2是先手。故需要两个函数来进行递归。
先手函数:当left==right,只剩一张牌了,那肯定是先手的拿这张牌,所以返回这张牌。若不止一张牌,那么先手就要在这两种情况中选取较大值:
拿掉左边的牌然后在剩下的纸牌中充当后手;
拿掉右边的牌然后在剩下的牌中充当后手。
后手函数:当left==right,只剩一张牌了,那么后手只能拿空气,所以返回零。若不止一张牌,那么后手要想怎么让对方下一次拿牌拿较小值。
拿掉左边的牌,在剩下的牌中充当先手;
拿掉右边的牌,在剩下的牌中充当先手。
2)由递归写出动态规划版本
·从递归函数看出,可变参为纸牌左右边界坐标left和right,他们的值是由总牌数决定的。也就是假设N张牌,left和right的范围均为0~N-1(先不考虑left实际上不会大于right)
那么我们可以确定表的大小,由于存在两个函数,所以需要两张表。
·我们再假设一组例子
int array[ ] = {3,5,7,4,3},考虑上述所说left和right的关系,表格中的下三角区域是不必考虑的。
·把目标格子和不依赖其他格子即可获得值的格子填上去,即只剩一张牌时(对角线),先手表中肯定是拿到牌的,而后手表拿空气,所以是零,如下图。
·然后我们再来看递归函数依赖情况,由此来确认表格元素的依赖关系。
先看先手,可看出是由后手表中坐标(left+1,right)的值加上array[left]的值和后手表中坐标(left,right-1)的值加上array[right]的值决定的,谁大,先手表中该位置就是该值。
同理可推出后手表,是由先手表中坐标(left+1,right)和(left,right-1)的值决定的。
找出依赖关系后尝试填一下表
例如点LR(0,1)= max(array[0]+后手表LR(1,1),array[1],后手表LR(0,0)) = 5
后手表中也同理,转移函数其实就是根据递归调用方式求出来的。
下面我们直接写出动态规划版本。