题目:
分析:
同一个轮次,,面对同样的L R,先手必然会选较大的值,后首面对的也是同样的L R,但因为是先手选完之后才选择,所以只能选其中较小的值
定义两个函数f()代表先手,它总是选最大值,
s()代表后手,他总是选最小值
动态规划一般原步骤:
1 确定被依赖的值,一般的第一列,第一行,最后一行等等这些值,用来作为依赖,后面的数据依赖它而产生,
分析递归代码,对于f,由LR,return list[i],可以先确定上图70-100-1-4这条lr斜线上的值,而对于s,这个值都是0,所以先填充这一列
2 确定填充的方向,顺序从[0][0]开始,或者倒序从[n][0]开始,对于本例,一般位置的格子的数据来自L+1,R-1,即左边和下方的位置,因此可以确定方向是左上到右下斜线的方向,上图红线
3,确定值的依赖,L+1,R-1
4确定但会数据的坐标,一般看主函数递归调用的传参,本例中为为[0][len(list)-1],即第一行最后一个位置
代码:
package main
package main
import(
"fmt"
"math"
)
func f(list []int,L,R int)int{
if L==R{
return list[L]
}
//选择拿左边/右边,加上我选择之后的后手拿牌的数,哪个大选哪个
return int(math.Max(float64(list[L]+s(list,L+1,R)),float64(list[R]+s(list,L,R-1))))
}
func s(list []int,L,R int)int{
if L==R{
return 0//只剩一张牌,被先手拿走,剩余0
}
return int(math.Min(float64(f(list,L+1,R)),float64(f(list,L,R-1))))
}
//两个二维表,f先手,s后手,先手后手用两个表中的数据互相依赖填充
//表中的数据相当与递归函数返回的结果
//一般位置的格子的数据依赖左边和下边的格子,因此由左上斜向下填充
func process(list []int){
//准备两个n*n的二位数组范别记录先手后手的数据
f:=[][]int{}
s:=[][]int{}
for t:=0;t<len(list);t++{
var tmp []int=make([]int,len(list))
var tmp1 []int=make([]int,len(list))
f=append(f,tmp)
s=append(s,tmp1)
}
// fmt.Println(f)
//我这里直接把L==R的数据填好,后面的数据依赖这组数据
for i :=0;i<len(list);i++{
for j :=0;j<len(list);j++{
if i<=j{
// fmt.Printf(" iiiii jjjjjj %v %v \n ",i,j)
if i==j{
f[i][j]=list[i]
s[i][j]=0
}
}
}
}
//开始填入一般数据,在L<R的区域,沿着左上往右下斜线填入,因为数据要依赖L+1和R-1(正下和正左)
i:=0
j:=1
start:=j//辅助换到下一斜线继续填数据
for i <j && i<len(list) &&j<=len(list)-1 {
// fmt.Printf(" iiiii <<<<<<<<<<<<<<<<<<<<, jjjjjj %v %v \n ",i,j)
f[i][j]=int(math.Max(float64(list[i]+s[i+1][j]),float64(list[j]+s[i][j-1])))
// fmt.Println(f)
s[i][j]=int(math.Min(float64(f[i+1][j]),float64(f[i][j-1])))
// fmt.Println(s)
i+=1
j+=1
//当列超出后,i回到第一行,j回到上一次初始j+1
if j==len(list){
j=start+(j-i)
i=0
}
}
//返回[0][len-1]处的值
fmt.Println(f[0][len(list)-1])
fmt.Println(s[0][len(list)-1])
}
func main(){
// list:=[]int{53, 40, 6, 48, 1, 51, 35, 46, 16, 23, 32}
list:=[]int{70,100,1,4}
fmt.Println(int(math.Max(float64(f(list,0,len(list)-1)),float64(s(list,0,len(list)-1)))))
process(list)
}
总结:
//两个二维表,f先手,s后手,先手后手用两个表中的数据互相依赖填充
//表中的数据相当与递归函数返回的结果
//一般位置的格子的数据依赖左边和下边的格子,因此由左上斜向下填充
//切片append操作会申请内存,效率不高,所以在new slice的时候最好固定cap