藍橋杯訓練:合併石子
阿新 • • 發佈:2019-02-13
問題描述
在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合併,合併後放在兩堆的中間位置,合併的費用為兩堆石子的總數。求把所有石子合併成一堆的最小花費。
輸入格式
輸入第一行包含一個整數n,表示石子的堆數。
接下來一行,包含n個整數,按順序給出每堆石子的大小 。
輸出格式
輸出一個整數,表示合併的最小花費。
樣例輸入
5
1 2 3 4 5
樣例輸出
33
資料規模和約定
1<=n<=1000, 每堆石子至少1顆,最多10000顆。
package 藍橋杯訓練題;
import java.util.Arrays;
import java.util.Scanner;
/*
思路:一看題目大概就猜到往動態規劃方面上寫,n堆石子需要合併,即[0:n-1]需要合併就必須得到[0:k]和[k+1:n-1]的費用代價,0<=k<n,列舉k值得到一個最小代價值再加上[0:n-1]數目的總和就可以了。得到遞推式
m[i][j] = min{m[i][k]+m[k+1][j] | 0<=i<=n,i<=j<=n,i<=k<j} + sum[i][j],其中m[i][j]表示合併第i堆到第j堆的最小費用,sum[i][j]表示第i堆到第j堆的數量總和
*/
public class 合併石子 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] arr = new int[n];
for(int i=0;i<n;i++)
arr[i] = in.nextInt();
int[][] m = new int[n][n]; //m[i][j]表示合併第i堆到第j堆的最小費用
int[][] sum = new int[n][n];//sum[i][j]表示i到j的個數總和
for(int i=0;i<n;i++){
sum[i][i] = arr[i];
for(int j=i+1;j<n;j++)
sum[i][j] = sum[i][j-1] + arr[j];
}
for(int length = 2; length<=n;length++){ //區間長度
for(int i = 0;i <= n-length; i++){//列舉起始長度
int j = i+length -1;
m[i][j] = m[i][i] + m[i+1 ][j];
for(int k=i+1;k<j;k++)
m[i][j] = m[i][j]<m[i][k]+m[k+1][j]?m[i][j]:m[i][k]+m[k+1][j];
m[i][j] += sum[i][j];
}
}
System.out.println(m[0][n-1]);
}
}