蓝桥杯训练:合并石子

来源:互联网 发布:matlab求矩阵的相角 编辑:程序博客网 时间:2024/06/09 12:34

问题描述
  在一条直线上有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]);}}