1:題目描述
作者:海森堡CSQ
鏈接:https://www.nowcoder.com/discuss/391530?type=post&order=time&pos=&page=1
來源:牛客網
第一題,給定一個數組n,比如
5 10 5 4 4
1 7 8 4 0
3 4 9 0 3
從每一列選擇一個數,求出后一列減去前一列的絕對值的和的最小值
比如這里就是5 4 5 4 4,所以輸出是5
2:解題思路
本地我們經過分析,可以明確發現本列最短路徑和下一列最短路徑之間有很大的關系,我們可以使用動態規划的思想解決這個問題;
- 狀態定義:如何定義出可以找到轉移方程的狀態,是這個問題的關鍵。我們分析發現相鄰兩列之間的最短路徑之間關系如下;假設dp[0],dp[1]和dp[2]分別代表從第一列到達此列的第0行數,第1行數,第2行數的最短路徑,那么到達后一列的第0行,第1行和第2行的最短路徑和dp[0],dp[1],dp[2]有什么關系尼?顯然假設后一列第0行,第1行,第2行的最短路徑分別為next[0],next[1],next[2],第0行數據為 n[0],第1行數據為 n[1],第2行數據為 n[2],則有,next[0] = min(abs(dp[0]-n[0]),abs(dp[1]-n[0]),abs(dp[2]-n[0]))。這是什么含義尼?就是本列的三行分別到n[0]處的路徑中最短一個就為最短一個。所以定義狀態dp[0],dp[1],dp[2]分別待變到達本列第0行,第1行,第2行的最短路徑。
- 轉移方程:正如上面個描述的那樣
- next[0] = min(abs(dp[0]-n[0]),abs(dp[1]-n[0]),abs(dp[2]-n[0]))。
- next[1] = min(abs(dp[0]-n[1]),abs(dp[1]-n[1]),abs(dp[2]-n[1]))。
- next[2] = min(abs(dp[0]-n[2]),abs(dp[1]-n[2]),abs(dp[2]-n[2]))。
- 暫存結果:使用dp[0],dp[1],dp[2]來保存上面的next結果,為后面的循環做准備。
3:代碼示例
package NiuKe; /** * @author :dazhu * @date :Created in 2020/3/20 18:50 * @description:AC測試 * @modified By: * @version: $ */ import java.util.*; public class Main { static int n; static int[][] array; static int postTemp = 0;//下一列選擇地值 static int curTemp = 0;//當前列選擇地值 static int resultSum = 0;//當前和 public static void main(String[] args) { Scanner sc = new Scanner(System.in); n = sc.nextInt(); array = new int[3][n]; for(int i = 0; i < 3; i++){ for(int j = 0; j < n; j++){ array[i][j] = sc.nextInt(); } } System.out.println(getMin(array)); } public static int getMin(int[][]array){ if(array[0].length ==1){ return 0; } int[] dp = new int[]{0,0,0}; int[] temp = new int[]{0,0,0}; //1 2 3 4 5 //2 3 4 5 6 //23 45 12 5 2 for(int i=1;i<n;i++){//外循環控制列數 for(int j=0;j<3;j++){//內訓還控制行數 //按照狀態轉移方程,更新的新的最短路徑 temp[j] = Math.min(Math.min(Math.abs(array[j][i] - array[0][i-1]) + dp[0], Math.abs(array[j][i] - array[1][i-1]) + dp[1]), Math.abs(array[j][i] - array[2][i-1]) + dp[2]); } //寄存結果 for(int k=0;k<3;k++){ dp[k] = temp[k]; } } return Math.min(Math.min(dp[0], dp[1]),dp[2]); } }
