典型的动态规划
从左上角触发,每次向右或向下走,最后到达右下角,我们要求的是初始值的血 dp[i][j] 从arr[i][j] 位置到右下角最少需要多少血 dp[m-1][n-1] = arr[m-1][n-1] > 0 ? 1:-arr[m-1][n-1] +1 //能到达的下一个位置 -去当前位置的值,如果为-标示要加血,如果为正标示要减学 dp[m-1][j] = max( dp[m-1][j+1] -arr[m-1][j],1 ) dp[i][n-1] = max( dp[i+1][n-1] - arr[i][n-1] ,1) dp[i][j] = min( max(dp[i][j+1] - arr[i][j],1),max(dp[i+1][j] - arr[i][j],1) )
至于空间压缩
压缩空间,首先基于经典解法,一般压缩掉外循环的维度,内循环 通过 更新前,更新后,或者调整更新顺序替代 为需要的元素
代码
package main import ( "fmt" ) func main(){ var n,m int fmt.Scanln(&n,&m) arr := make([][]int,n) for i:=0;i<n;i++{ arr[i] = make([]int,m) for j:=0;j<m;j++{ fmt.Scanf("%d",&arr[i][j]) } } helper2(arr,n,m) return } func helper2(arr [][]int,n,m int){ dp := make([]int,n) dp[m-1] = 1 if arr[n-1][m-1] < 0{ dp[m-1] = -arr[n-1][m-1]+1 } for j:=m-2;j>=0;j--{ dp[j] = max(dp[j+1] - arr[n-1][j],1) } for i:=n-2;i>=0;i--{ dp[m-1] = max(dp[m-1] - arr[i][m-1],1) for j:=m-2;j>=0;j--{ //dp[j+1] 等同于 dp[i][j+1] dp[j] 等同于 dp[i+1][j] 因为dp[j] 在更新之前 right := max(dp[j+1] - arr[i][j],1) down := max(dp[j] - arr[i][j],1) dp[j] = min(right,down) //pre = dp[j] } } fmt.Println(dp[0]) return } func helper(arr [][]int,n,m int){ dp := make([][]int,n) for i:=0;i<n;i++{ dp[i] = make([]int,m) } dp[n-1][m-1] = 1 if arr[n-1][m-1] < 0{ dp[n-1][m-1] = -arr[n-1][m-1]+1 } /*for i:=n-2;i>=0;i--{ dp[i][m-1] = max(dp[i+1][m-1] - arr[i][m-1],1) }*/ for j:=m-2;j>=0;j--{ dp[n-1][j] = max(dp[n-1][j+1] - arr[n-1][j],1) } for i:=n-2;i>=0;i--{ dp[i][m-1] = max(dp[i+1][m-1] - arr[i][m-1],1) for j:=m-2;j>=0;j--{ right := max(dp[i][j+1] - arr[i][j],1) down := max(dp[i+1][j] - arr[i][j],1) dp[i][j] = min(right,down) } } fmt.Println(dp[0][0]) return } func min(a,b int) int { if a < b { return a } return b } func max(a,b int) int { if a < b { return b } return a }