算法笔记_083:蓝桥杯练习 合并石子(Java)
目录
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); } }
每天一小步,成就一大步