AcWing刷题——石子合并(区间DP)

题目描述:

设有 N 堆石子排成一排,其编号为 123N

每堆石子有一定的质量,可以用一个整数来描述,现在要将这 N堆石子合并成为一堆。

每次只能合并相邻的两堆,合并的代价为这两堆石子的质量之和,合并后与这两堆石子相邻的石子将和新堆相邻,合并时由于选择的顺序不同,合并的总代价也不相同。

例如有 4堆石子分别为 1 3 5 2, 我们可以先合并 12 堆,代价为 4,得到 4 5 2, 又合并 12 堆,代价为 9,得到 9 2 ,再合并得到 11,总代价为 4+9+11=24;如果第二步是先合并 23堆,则代价为 7,得到 4 7,最后一次合并代价为 11,总代价为 4+7+11=22

问题是:找出一种合理的方法,使总的代价最小,输出最小代价。

输入格式

第一行一个数 N表示石子的堆数 N

第二行 N个数,表示每堆石子的质量(均不超过 1000)。

输出格式

输出一个整数,表示最小代价。

数据范围

1N300

输入样例:

4
1 3 5 2

输出样例:

22

分析:

第一次写区间DP的题目,一时没有思路,下不去手,然后就去网上查阅相关区间dp算法的资料,又去看了别人的题解才懂了一下,下面的代码也是根据别人代码改写的,希望自己后面遇到类似的区间DP问题能回来再看看。这里用到了前缀和。

AC代码:

 1 import java.util.Scanner;
 2 
 3 public class Main {
 4     public static void main(String[] args) {
 5         Scanner input = new Scanner(System.in);
 6         int n = input.nextInt();
 7         
 8         // 定义一个prefix数组,用于存储前i个数的和,简称前缀和
 9         int[] prefix = new int[n + 1];
10         
11         for (int i = 1; i <= n; i++) {
12             int a = input.nextInt();
13             prefix[i] = prefix[i - 1] + a;
14         }
15         
16         // 定义一个dp二维数组,用于存储区间(i,j)内合并的最小代价
17         int[][] dp = new int[n + 1][n + 1];
18         
19         
20         // 先枚举区间,从1开始
21         for (int len = 1; len < n; len++) {
22             // 再枚举左端点
23             for (int i = 1; i + len <= n; i++) {
24                 // 确定右端点
25                 int j = i + len;
26                 // 先设置为无穷大,不然永远都是0
27                 dp[i][j] = Integer.MAX_VALUE;
28                 // 枚举该区间的所有数
29                 // 这里为啥k不能取到j,就是因为区间的前端一定不能超过后端,如 dp[k + 1][j]
30                 for (int k = i; k < j; k++) {
31                     // dp[i][k] + dp[k + 1][j] 这是之前分别合并i 到 k区间和k + 1到j区间的最小代价
32                     // 而prefix[j] - prefix[i - 1]才是此时合并i 到 j区间的最小代价
33                     // 因为合并之后两堆石头总数量不变,所以仍然需要i 到 j之间的石头和总数作为此时合并的代价
34                     dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k + 1][j] + (prefix[j] - prefix[i - 1]));
35                 }
36             }
37         }
38         
39         System.out.println(dp[1][n]);
40     }
41 }

 把AcWing题目上的链接放在这,下次回忆起来再去做一遍https://www.acwing.com/problem/content/284/

posted @ 2021-04-03 20:38  没有你哪有我  阅读(115)  评论(0编辑  收藏  举报