目錄
1 問題描述
問題描述
在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合並,合並后放在兩堆的中間位置,合並的費用為兩堆石子的總數。求把所有石子合並成一堆的最小花費。
輸入格式
輸入第一行包含一個整數n,表示石子的堆數。
接下來一行,包含n個整數,按順序給出每堆石子的大小 。
接下來一行,包含n個整數,按順序給出每堆石子的大小 。
輸出格式
輸出一個整數,表示合並的最小花費。
樣例輸入
5
1 2 3 4 5
1 2 3 4 5
樣例輸出
33
數據規模和約定
1<=n<=1000, 每堆石子至少1顆,最多10000顆。
2 解決方案
本題主要考查動態規划法思想。
剛開始做的時候,使用貪心法求解,即每次選擇相鄰兩個和為最小的一組合成堆,結果評分為10分,后來仔細想了一下,貪心法不能達到最優解,唯有使用動態規划法求解。
該題幾乎和訓練題集中的矩陣相乘一樣,具體思想講解,請參考本人另一篇博客:算法筆記_081:藍橋杯練習 算法提高 矩陣乘法(Java)
具體代碼如下:
import java.util.Scanner; public class Main { public long getSum(long[] A, int a, int b) { long sum = 0; for(int i = a;i <= b;i++) sum += A[i]; return sum; } public void printResult(long[] A) { if(A.length == 1) { System.out.println(A[0]); return; } long[][] dp = new long[A.length + 1][A.length + 1]; for(int len = 2;len <= A.length;len++) { for(int i = 1, j = len;j <= A.length;i++,j++) { long min = Long.MAX_VALUE; for(int k = i;k < j;k++) { if(min > dp[i][k] + dp[k + 1][j] + getSum(A, i - 1, j - 1)) min = dp[i][k] + dp[k + 1][j] + getSum(A, i - 1, j - 1); } dp[i][j] = min; } } System.out.println(dp[1][A.length]); return; } public static void main(String[] args) { Main test = new Main(); Scanner in = new Scanner(System.in); int n = in.nextInt(); if(n < 1 || n > 1000) return; long[] A = new long[n]; for(int i = 0;i < n;i++) { A[i] = in.nextLong(); } test.printResult(A); } }