1. 程式人生 > >藍橋杯訓練:合併石子

藍橋杯訓練:合併石子

問題描述
  在一條直線上有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]); } }