解题思路:

将n堆石子合并成一堆且每次只能合并相邻的两堆,

所以第n-1即最后一次合并肯定是由两堆变一堆

假设两堆的区间长度分别为[1,x][x+1,n]

而对那两堆的每一堆而言肯定是由更小的两堆合并过来的

即[1,x]肯定是由[1,a][a+1,x]合并来的,[x+1,n]是由[x+1,b],[b+1,n]合并来的

不断往前推发现,区间的长度在不断变小,那么区间的边界情况是什么?

当然是区间长度为1时,因为 此时的区间长度达到最小,不可能更小了,对于区间[a,a]而言,只包括了一堆石子,此时无法进行合并,故消耗代价为0

而DP的过程又是递推的过程,关键是找到递推的公式和边界

对于此题,我既然已经知道最大的区间答案是由小区间推过来的,那我只要保证小区间的和最优即保证了大区间的结果最优

递推公式:dp[l][r]=min[dp[l][r],dp[l][k]+dp[k+1][r]+sum[r]-sum[l-1])

递推边界:dp[i][i]=0 

对于dp[i][j]的理解i-j区间的所有石子合并为一堆消耗的最小代价

我们求得答案是dp[1][n]即区间1-5所有石子合并成一堆消耗的最小代价

屏幕截图 2024-02-23 120437.png


屏幕截图 2024-02-23 120458.png

注意事项:


参考代码:

import java.io.*;
import java.util.*;
 
  public class Main{
      static BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
      static PrintWriter pw =new PrintWriter(new OutputStreamWriter(System.out));
      public static void main(String[]args) throws IOException{
          int n=Integer.parseInt(br.readLine());
          int []arr=new int[n+1];
          long []sum=new long [n+1];
          long [][]dp=new long[n+1][n+1];
          String []s=br.readLine().split(" ");
        for(int i=1;i<=n;i++){
            Arrays.fill(dp[i],Long.MAX_VALUE);//初始化正无穷
        }
          for(int i=1;i<=n;i++){
              arr[i]=Integer.parseInt(s[i-1]);
              sum[i]=sum[i-1]+arr[i];//前缀和 
              dp[i][i]=0;
          }
          //区间DP模板 三层for
          for(int len=2;len<=n;len++){   //阶段:枚举区间长度
              for(int l=1;l+len-1<=n;l++){//状态:枚举区间起点
                  int r=len+l-1;//区间终点
                  for(int k=l;k<r;k++){  //决策:枚举分割点
                      dp[l][r]=Math.min(dp[l][r],dp[l][k]+dp[k+1][r]+sum[r]-sum[l-1]);
                   }
              }
          }
          pw.println(dp[1][n]);
          pw.flush();
      }
  }


点赞(0)
 

0.0分

1 人评分

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

评论列表 共有 0 条评论

暂无评论