算法筆記_083:藍橋杯練習 合並石子(Java)


目錄

1 問題描述

2 解決方案

 


1 問題描述

問題描述
  在一條直線上有n堆石子,每堆有一定的數量,每次可以將兩堆相鄰的石子合並,合並后放在兩堆的中間位置,合並的費用為兩堆石子的總數。求把所有石子合並成一堆的最小花費。
輸入格式
  輸入第一行包含一個整數n,表示石子的堆數。
  接下來一行,包含n個整數,按順序給出每堆石子的大小 。
輸出格式
  輸出一個整數,表示合並的最小花費。
樣例輸入
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);
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM