写在前面:
就当写个LOG,自19年4月更换工作,一直处于忙碌的状态,最近虽然复工了,但是由于yq影响和合同到期,工作并不多,所以有时间研究一下自己感兴趣的东西。顺便有问题请,大家指出来。 我写动态规划也是新手,大学数据几乎忘光所以很难抽象数学公式。
有 N 堆金币排成一排,第 i 堆中有 C[i] 块金币。每次合并都会将相邻的两堆金币合并为一堆,成本为这两堆金币块数之和。经过N-1次合并,最终将所有金币合并为一堆。请找出将金币合并为一堆的最低成本。
其中,1 <= N <= 30,1 <= C[i] <= 100
输入描述:
第一行输入一个数字 N 表示有 N 堆金币
第二行输入 N 个数字表示每堆金币的数量 C[i]
输出描述:
输出一个数字 S 表示最小的合并成一堆的成本
输入示例1:
4
3 2 4 1
输入示例1:
20
析题:
首先要搞懂这个问题,首先明白什么是区间动态规划,这里感谢下面这个文章的老哥,介绍给我什么是动态规划以及算法模板。
https://blog.csdn.net/qq_40772692/article/details/80183248
这里,我先介绍我的想法,我对动态规划这个算法没有上过具体的课程,也是靠平时数学基础来得到结果先看一下我的思路。可能百分之80%的都能想到。
按照提意,两两合并。假设每次只有两堆金币进行合并那么就会出现一下这几种情况。
定义参数
int[] jinbi=[3,2,4,1];
固定合并为jinbi[0],那么就会出现下面几种状况;
(1) jinbi[0]+jinbi[1] = 5
(jinbi[0]+jinbi[1])+jinbi[2]=9
((jinbi[0]+jinbi[1])+jinbi[2])+jibi[3] = 10
结果为24
(2) jinbi[0]+jinbi[1] = 5
jinbi[2]+jinbi[3] = 5
(jinbi[0]+jinbi[1])+(jinbi[2]+jinbi[3]) = 10
结果为20
以此类推,其他的项
推广到N项时:怎么抽象出来?
根据上面那篇文章的老哥介绍的核心思路我这里在赘述一下。
既然让我求解在一个区间上的最优解,那么我把这个区间分割成一个个小区间,求解每个小区间的最优解,再合并小区间得到大区间即可。所以在代码实现上,我可以枚举区间长度len为每次分割成的小区间长度(由短到长不断合并),内层枚举该长度下可以的起点,自然终点也就明了了。然后在这个起点终点之间枚举分割点,求解这段小区间在某个分割点下的最优解。
————————————————
版权声明:本文为CSDN博主「阿阿阿安」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40772692/article/details/80183248
for(int len = 1;len<=n;len++){//枚举长度
for(int j = 1;j+len<=n+1;j++){//枚举起点,ends<=n
int ends = j+len - 1;
for(int i = j;i<ends;i++){//枚举分割点,更新小区间最优解
dp[j][ends] = min(dp[j][ends],dp[j][i]+dp[i+1][ends]+something);
}
}
}
那么 根据资料可以变成这样,但是根据答案我有几处参数的具体定义不清楚 下面是代码
package wkx.leetCode;
import java.util.Scanner;
/**
* 有 N 堆金币排成一排,第 i 堆中有 C[i] 块金币。
* 每次合并都会将相邻的两堆金币合并为一堆,成本为这两堆金币块数之和。
* 经过N-1次合并,最终将所有金币合并为一堆。
* 请找出将金币合并为一堆的最低成本。
* <p>
* 其中,1 <= N <= 30,1 <= C[i] <= 100
*/
public class test1 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int[] jinbi = new int[n];
int[] sum = new int[n];
for (int i = 0; i < n; i++) {
jinbi[i] = in.nextInt();
if (i == 0) sum[i] = jinbi[i];
else sum[i] = sum[i - 1] + jinbi[i];
}
in.close();
long temp = 0;
long min = 0;
long[][] dp = new long[n][n];
for (int l = 1; l < n; l++) {//枚举长度
System.out.println("l=" + l);
for (int i = 0; i < n && i + l < n; i++) { //枚举起点 枚举终点ends<= n-1
System.out.println(" i=" + i);
min = dp[i][i] + dp[i + 1][i + l];//最小值
System.out.println(" dp[i][i]:dp[" + i + "][" + i + "]=" + dp[i][i]);
System.out.println(" dp[i + 1][i + l]:dp[" + (i + 1) + "][" + (i + l) + "]=" + dp[i + 1][i + l]);
System.out.println(" min = " + min);
for (int k = i + 1; k <= i + l - 1; k++) {//枚举分割点
System.out.println(" k=" + k);
temp = dp[i][k] + dp[k + 1][i + l];//其他步数的最小值
System.out.println(" dp[i][k]:dp[" + i + "][" + k + "]=" + dp[i][k]);
System.out.println(" dp[k + 1][i + l]:dp[" + (k + 1) + "][" + (i + l) + "]=" + dp[k + 1][i + l]);
System.out.println(" temp = " + temp);
System.out.println(" temp < min = " + (temp < min));
if (temp < min) {
min = temp;
System.out.println(" min = " + min);
}
}
System.out.println(" i > 0 =" + (i > 0));
if (i > 0) {
dp[i][i + l] = min + sum[i + l] - sum[i - 1];
System.out.println(" min=" + min);
System.out.println(" sum[i + l]:sum[" + (i + l) + "]=" + sum[i + l]);
System.out.println(" sum[i - 1]:sum [" + (i - 1) + "]= " + sum[i - 1]);
System.out.println(" dp[i][i + l]:dp[" + i + "][" + (i + l) + "]=" + dp[i][i + l]);
} else {
dp[i][i + l] = min + sum[l];
System.out.println(" min=" + min);
System.out.println(" sum[" + l + "]=" + sum[l]);
System.out.println(" dp[" + i + "][" + (i + l) + "]=" + dp[i][i + l]);
}
}
}
System.out.println(dp[0][n - 1]);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(dp[i][j] + " ");
}
System.out.println();
}
}
}