石子合并问题报告
石子归并(动态规划)
石子归并(动态规划)动态规划石子合并问题【石材加固】在一个圆形操场的四周摆放着n堆石子。
现要将石子有次序地合并成一堆。
规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。
尝试设计一个算法来计算将n堆石头合并成一堆的最小分数和最大分数。
[输入文件]包含两行,第1行是正整数n(1<=n<=100),表示有n堆石子。
第2行有n个数,分别表示每堆石子的个数。
【输出文件】输出两行。
第1行中的数字是最低分数;第2行中的数字是最高分。
[输入示例]44459[输出示例]4354【分析】起初,我以为贪心法可以解决这个问题,但事实上,由于必须有两个相邻的桩合并,贪心法不能保证每次都能得到所有桩中石头数量最多的两个桩。
例如,以下示例:6346542如果使用贪心法计算最小分数,则应为以下合并步骤:第一次合并3465422,3合并分数为5,第二次合并546545,4合并分数为9,第三次合并96545,4合并分数为9,第四次合并9699,6合并分数为15,第五次合并15915,9合并分数为24,总分=5+9+9+15+24=62但是如果采用如下合并方法,却可以得到比上面得分更少的方法:第一次合并3465423,4合并得分是7第二次合并765427,6合并得分是13第三次合并135424,2合并得分是6第四次合并13565,6合并得分是11第五次合并131113,11合并得分是24总得分=7+13+6+11+24=61因此,我们知道这个问题不能用贪婪的方法来解决。
在上面的例子中,相邻的两个石子数量分别为13和11的桩第五次合并。
第一堆、第二堆和第三堆(石块数量分别为3、4和6)以及第四、第五和第六堆(石块数量分别为5、4和2)组合四次后形成两堆石块。
所以问题归结为如何使两个子序列的N-2组合分数之和达到最优。
为了实现这一目标,我们将第一个序列分为两个:第一和第二堆形成子序列1,第三堆形成子序列2。
动态规划-石子合并问题
动态规划-⽯⼦合并问题(1)问题描述 在⼀个圆形操场的四周摆放着 num 堆⽯⼦。
先要将⽯⼦有次序地合并成⼀堆。
规定每次只能选相邻的 2 堆⽯⼦合并成新的⼀堆,并将新的⼀堆⽯⼦数记为该次合并的耗费⼒⽓。
试设计⼀个算法,计算将 n 堆⽯⼦合并成⼀堆的最省⼒⽓数。
(2)算法思想 对于给定的 n 堆⽯⼦,当只有⼀堆时,不⽤搬,进⽽不耗费⼒⽓,然后依次计算出从 2 堆 ~ num 堆⽯⼦的最优解,并且堆数递增求最优解,依赖于上⼀步的解进⾏计算所得;(3)算法思路 此解法和矩阵连乘类似,我们知道矩阵连乘也是每次合并相邻的两个矩阵,那么⽯⼦合并可以⽤矩阵连乘的⽅式来解决。
设 dp[i][j] 表⽰第 i 到第 j 堆⽯⼦合并的最优值,sum[i][j] 表⽰第 i 到第 j 堆⽯⼦的所耗费的⼒⽓总数。
动规⽅程如下:(4)代码展⽰public class StoneMerge {/*** 记录⽯⼦堆的数量*/private static int num;/*** 记录每堆⽯⼦的重量*/private static int[] weight;/*** 记录⽯⼦堆断开的位置【便于计算局部最优解】*/private static int[][] location;/*** 记录⽯⼦堆局部最优解,以⾄于求得最终最优解【动规⽅程】*/private static int[][] dp;/*** 初始化数据*/private static void initData() {Scanner input = new Scanner(System.in);System.out.println("请输⼊⽯⼦堆数量:");num = input.nextInt();weight = new int[num];System.out.println("请输⼊每堆⽯⼦的重量:");for (int i = 0; i < weight.length; i++) {weight[i] = input.nextInt();}// 定义成 int 类型的⼆维数组,创建完每个元素直接初始化为 0dp = new int[num][num];location = new int[num][num];}/*** 计算最省最费⼒⽓值*/private static void dpFindMinStrength() {// 初始化 dp 数组for (int m = 0; m < num; m++) {dp[m][m] = 0; // ⼀堆⽯⼦,不⽤搬,耗费⼒⽓为 0}for (int r = 2; r <= num; r++) { // 从 2 堆依次到 num 堆,分别计算最优值for (int i = 0; i < num - r + 1; i++) { // 起始⽯⼦堆取值范围int j = i + r - 1; // 根据每次选取⽯⼦堆 r 和起始⽯⼦堆 i ,计算终⽌⽯⼦堆int sum = 0;for (int x = i; x <= j; x++) { // 计算从⽯⼦堆 i 到⽯⼦堆 j 合并时,最后两堆使⽤的⼒⽓总和 sumsum += weight[x];}// 根据动规⽅程,从局部最优解中计算当前从⽯⼦堆 i 到⽯⼦堆 j 合并所使⽤的的⼒⽓总和dp[i][j] = dp[i + 1][j] + sum; // 计算从 i ⽯⼦堆分开时,使⽤的⼒⽓总和location[i][j] = i; // 标记从第 i ⽯⼦堆分开位置for (int k = i + 1; k < j; k++) { // 需要统计从 k 【k ∈ (i, j)】⽯⼦堆分开,使⽤的⼒⽓总和int temp = dp[i][k] + dp[k + 1][j] + sum; // 计算从 k ⽯⼦堆分开时,使⽤的⼒⽓总和if (temp < dp[i][j]) {dp[i][j] = temp;location[i][j] = k;}}}}}/*** 输出*/private static void print() {System.out.println("动规数组【不同堆数合并⽯⼦所费⼒⽓】:");for (int i = 0; i < num; i++) {for (int j = 0; j < num; j++) {System.out.print(dp[i][j] + " ");}System.out.println();}System.out.println("不同堆数合并⽯⼦最省⼒⽓断开位置最优解:");for (int i = 0; i < num; i++) {for (int j = 0; j < num; j++) {System.out.print(location[i][j] + " ");}System.out.println();}}public static void main(String[] args) {// 初始化数据initData();// 计算最省最费⼒⽓值dpFindMinStrength();// 输出print();}}⽯⼦合并核⼼代码(5)输⼊输出请输⼊⽯⼦堆数量:4请输⼊每堆⽯⼦的重量:4 45 9动规数组【不同堆数合并⽯⼦所费⼒⽓】:0 8 21 430 0 9 270 0 0 140 0 0 0不同堆数合并⽯⼦最省⼒⽓分开位置最优解【下标从数组 0 开始分开】:0 0 1 20 0 1 20 0 0 20 0 0 0输⼊输出(6)总结 ⽯⼦合并问题完全提现了动态规划的核⼼思想,先求解⼦问题的解【⼦问题求解不相互独⽴,相互依赖】,然后从这些⼦问题的解中得到原问题的解,进⽽得到该问题的最优解。
石子合并问题
石子合并问题
石子合并问题是最经典的DP问题。
首先它有如下3种题型:
(1)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动任意的2堆石子合并,合并花费为新合成的一堆石子的数量。
求将这N堆石子合并成一堆的总花费最小(或最大)。
分析:当然这种情况是最简单的情况,合并的是任意两堆,直接贪心即可,每次选择最小的两堆合并。
本问题实际上就是哈夫曼的变形。
(2)有N堆石子,现要将石子有序的合并成一堆,规定如下:每次只能移动相邻的2堆石子合并,合并花费为新合成的一堆石子的数量。
求将这N堆石子合并成一堆的总花费最小(或最大)。
分析:我们熟悉矩阵连乘,知道矩阵连乘也是每次合并相邻的两个矩阵,那么石子合并可以用矩阵连乘的方式来解决。
设dp[i][j]表示第i到第j堆石子合并的最优值,sum[i][j]表示第i到第j 堆石子的总数量。
那么就有状态转移公式:
代码如下:(直线)
return 0;
}
(3)问题(2)的是在石子排列是直线情况下的解法,如果把石子改为环形排列,又怎么做呢?
分析:状态转移方程为:
其中有:
代码如下:(环形)
#include <stdio.h>
#include <string.h>
#define INF 10000
#define N 205
int mins[N][N];
int maxs[N][N];
int sum[N],a[N];
int minval,maxval;
int n;
int min(int a,int b)
{
return a<b?a:b;。
动态规划思想:石子合并问题
动态规划思想:⽯⼦合并问题描述:在⼀个圆形操场的四周摆放着n 堆⽯⼦。
现要将⽯⼦有次序地合并成⼀堆。
规定每次只能选相邻的2 堆⽯⼦合并成新的⼀堆,并将新的⼀堆⽯⼦数记为该次合并的得分。
试设计⼀个算法,计算出将n堆⽯⼦合并成⼀堆的最⼩得分和最⼤得分。
开始以为通过贪⼼算法可能很快解决问题,可是是⾏不通的。
⾸先我们可以把这么堆⽯⼦看成⼀列我们假如5堆的⽯⼦,其中⽯⼦数分别为7,6,5,7,100•按照贪⼼法,合并的过程如下:每次合并得分第⼀次合并 7 6 5 7 100 =11 第⼆次合并 7 11 7 100=18 第三次合并 18 7 100 =25第四次合并 25 100 =125总得分=11+18+25+125=179•另⼀种合并⽅案每次合并得分 第⼀次合并 7 6 5 7 100 ->13第⼆次合并 13 5 7 100->12第三次合并 13 12 100 ->25第四次合并 25 100 ->125总得分=13+12+25+125=175显然利⽤贪⼼来做是错误的,贪⼼算法在⼦过程中得出的解只是局部最优,⽽不能保证使得全局的值最优。
如果N-1次合并的全局最优解包含了每⼀次合并的⼦问题的最优解,那么经这样的N-1次合并后的得分总和必然是最优的。
因此我们需要通过动态规划算法来求出最优解。
在此我们假设有n堆⽯⼦,⼀字排开,合并相邻两堆的⽯⼦,每合并两堆⽯⼦得到⼀个分数,最终合并后总分数最少的。
我们设m(i,j)定义为第i堆⽯⼦到第j堆⽯⼦合并后的最少总分数。
a(i)为第i堆⽯⼦得⽯⼦数量。
当合并的⽯⼦堆为1堆时,很明显m(i,i)的分数为0; 当合并的⽯⼦堆为2堆时,m(i,i+1)的分数为a(i)+a(i+1); 当合并的⽯⼦堆为3堆时,m(i,i+2)的分数为MIN((m(i,i)+m(i+1,i+2)+sum(i,i+2)),(m(i,i+1)+m(i+2,i+2)+sum(i,i+2)); 当合并的⽯⼦堆为4堆时......代码实现如下:1 #include<stdio.h>2#define N 1003/*4 *求合并过程中5 *最少合并堆数⽬6 **/7int MatrixChain_min(int p[N],int n)8 {9//定义⼆维数组m[i][j]来记录i到j的合并过成中最少⽯⼦数⽬10 //此处赋值为-11112int m[N][N];13for(int x=1;x<=n;x++)14for(int z=1;z<=n;z++)15 {16 m[x][z]=-1;17 }1819int min=0;2021//当⼀个单独合并时,m[i][i]设为0,表⽰没有⽯⼦22for(int g = 1;g<=n;g++) m[g][g]=0;2324//当相邻的两堆⽯⼦合并时,此时的m很容易可以看出是两者之和25for(int i=1;i<=n-1;i++)26 {27int j=i+1;28 m[i][j]=p[i]+p[j];29 }3031//当相邻的3堆以及到最后的n堆时,执⾏以下循环32for(int r=3; r<=n;r++)33for(int i=1;i<=n-r+1;i++)34 {35int j = i+r-1; //j总是距离i r-1的距离36int sum=0;37//当i到j堆⽯⼦合并时最后⾥⾯的⽯⼦数求和得sum38for(int b=i;b<=j;b++)39 sum+=p[b];4041// 此时m[i][j]为i~j堆⽯⼦间以m[i][i]+m[i+1][j]+sum结果,这是其中⼀种可能,不⼀定是最优42 //要与下⾯的情况相⽐较,唉,太详细了4344 m[i][j] = m[i+1][j]+sum;4546//除上⾯⼀种组合情况外的其他组合情况47for(int k=i+1;k<j;k++)48 {49int t=m[i][k]+m[k+1][j]+sum;50if(t<m[i][j])51 m[i][j] = t;5253 }54 }55//最终得到最优解56 min=m[1][n];57return min;585960 }6162/*63 *求合并过程中64 *最多合并堆数⽬65 **/6667int MatrixChain_max(int p[N],int n)68 {69int m[N][N];70for(int x=1;x<=n;x++)71for(int z=1;z<=n;z++)72 {73 m[x][z]=-1;74 }757677int max=0;78//⼀个独⾃组合时79for(int g = 1;g<=n;g++) m[g][g]=0;80//两个两两组合时81for(int i=1;i<=n-1;i++)82 {83int j=i+1;84 m[i][j]=p[i]+p[j];85 }8687for(int r=3; r<=n;r++)88for(int i=1;i<=n-r+1;i++)89 {90int j = i+r-1;91int sum=0;92for(int b=i;b<=j;b++)93 sum+=p[b];94 m[i][j] = m[i+1][j]+sum;9596for(int k=i+1;k<j;k++)97 {98int t=m[i][k]+m[k+1][j]+sum;99if(t>m[i][j])100 m[i][j] = t;101102 }103 }104105 max=m[1][n];106return max;107108109 }110int main()111 {112int stone[N];113int min=0;114int max=0;115int n;116 scanf("%d",&n);117for(int i=1;i<=n;i++)118 scanf("%d",&stone[i]);119120 min= MatrixChain_min(stone,n);121 max= MatrixChain_max(stone,n);122123//因为题⽬要求圆的原因,要把所有情况都要考虑到,总共有n种情况。
石子合并dp表达式
石子合并dp表达式
石子合并问题可以使用动态规划来解决。
对于有N堆石子的情况,设
dp[i][j]表示将i至j之间的石子合并成一堆的最小花费。
初始时,对于任意i,都有dp[i][i]=0,因为合并一堆石子不需要花费。
对于区间[i,j],枚举合并点k,则该区间合并的最小花费为:dp[i][k]+ dp[k+1][j]+sum[i][j],其中sum[i][j]表示区间[i,j]中石子数量的和。
最终答案即为dp[1][n]。
对于有N堆石子,每次只能移动相邻的2堆石子合并的情况,最终的结果
为dp[1][n],表示合并全部石子的最小代价。
以上内容仅供参考,建议查阅相关资料文献,或者咨询数学领域专业人士,以获取更全面准确的信息。
石子合并问题实验报告
一、实验目的1. 了解石子合并问题的背景和意义;2. 掌握石子合并问题的解决方法;3. 提高实验操作能力和数据分析能力。
二、实验原理石子合并问题是一个经典的数学问题,主要研究如何将若干个石子合并成若干个尽可能大的石子堆。
该问题在现实生活中具有广泛的应用,如城市规划、资源分配等。
实验通过模拟石子合并过程,寻找最优的合并策略。
三、实验材料1. 石子若干;2. 纸和笔;3. 计算器。
四、实验步骤1. 准备实验材料,将石子随机分成若干堆;2. 记录每堆石子的数量;3. 按照一定的合并策略进行合并,如从数量最少的一堆开始合并;4. 记录每次合并后的石子堆数量和数量;5. 重复步骤3和4,直到所有石子合并成若干个石子堆;6. 分析实验结果,总结最优合并策略。
五、实验结果与分析1. 实验结果通过多次实验,发现以下几种合并策略:(1)从数量最少的一堆开始合并;(2)从数量最多的一堆开始合并;(3)从数量相差最小的一堆开始合并。
2. 实验分析(1)从数量最少的一堆开始合并:该策略在合并过程中可以逐渐减少石子堆的数量,但可能导致石子堆的体积差异较大。
(2)从数量最多的一堆开始合并:该策略在合并过程中可以保持石子堆的体积相对稳定,但可能导致石子堆的数量较多。
(3)从数量相差最小的一堆开始合并:该策略在合并过程中可以平衡石子堆的数量和体积,但需要花费更多的时间进行筛选。
综上所述,从数量相差最小的一堆开始合并是一种较为合理的合并策略。
六、实验结论1. 通过石子合并问题实验,了解了石子合并问题的背景和意义;2. 掌握了石子合并问题的解决方法,即从数量相差最小的一堆开始合并;3. 提高了实验操作能力和数据分析能力。
七、实验心得1. 在实验过程中,要注重观察和分析,以便找到最优的合并策略;2. 要善于总结经验,提高实验效率;3. 要注重团队合作,共同完成实验任务。
八、实验展望石子合并问题在现实生活中具有广泛的应用,未来可以从以下几个方面进行深入研究:1. 探讨不同合并策略的优缺点,寻找更优的合并策略;2. 将石子合并问题与其他实际问题相结合,如城市规划、资源分配等;3. 利用计算机技术,模拟石子合并过程,提高实验效率。
合并石子问题的算法讨论
1 +2 + 3 + = 8 + 4 211 6 7 7 7 4
算法三、GARSIAWACHS算法
算法三、GARSIAWACHS算法
【引理1】
【引理2】
【引理2】Βιβλιοθήκη 【引理2】【引理2】
【引理3】
【引理4】
GARSIAWACHS算法实现
GARSIAWACHS算法实现
平衡树维护优化 对于这个算法,我们只需要维护一个2-递减
序列就可以了,算法的精髓在于每次寻找一个
最小的k。先把n个数从后往前扫一遍,将不满 足2-递减性质的数加进树中,每次更新序列时, 通过平衡树来维护,最后算法时间复杂度为 O(nlogn)。
总结
在证明GarsiaWachs算法的过程中,我们多次用 到反证法的思想,通过假设反例成立,推出矛盾来 证明,这是一种思想,运用这种思想,能够解决很
么我们就把a[k]与a[k-1]合并,之后向前找最大 的一个满足a[j-1]>a[k]+a[k-1]的j,把合并后的值 a[k]+a[k-1]插入a[j]的前面,最后的答案就是每 次a[k]与a[k-1]合并的代价和。
算法三、GARSIAWACHS算法
原数列: 20 6 10 11 25 12
20 371011 25 12 20616 37 12 12 27 47 25 25 20 11 27 20
算法三、 GARSIAWACHS算法
假设第i个石子的权值为a[i]。 对于节点k,如果a[k-1]>a[k+1],那
么,称节点k满足2-递减性质。
算法三、 GARSIAWACHS算法
GarsiaWachs算法大意:
石子合并问题原理
石子合并问题原理
石子合并问题是一个经典的动态规划问题。
假设有n堆石子,每堆石子的数量分别为a_1, a_2, ..., a_n。
当合并两堆石子时,合并的代价为两堆石子的数量之和。
最终目标是通过一系列合并操作,使得最终只剩下一堆石子,并且合并的总代价最小。
为了解决这个问题,可以使用动态规划的思想。
定义一个二维数组dp,其中dp[i][j]表示从第i堆石子到第j堆石子合并的最小代价。
当i=j时,即只有一堆石子,不需要进行任何合并,所以
dp[i][j]=0。
当i<j时,假设k是i和j之间的一个分割点,那么dp[i][j]的值可以通过枚举所有可能的分割点k来求得。
具体计算dp[i][j]的方法如下:
- 首先,将dp[i][j]初始化为一个较大的值,比如无穷大。
- 然后,枚举分割点k,计算合并左侧和右侧的代价,即
dp[i][k]+dp[k+1][j]+sum(a_i to a_j)。
- 最后,选取所有分割点中代价最小的那个作为dp[i][j]的值。
最终,dp[1][n]就是合并所有石子的最小代价。
实际上,可以通过动态规划的方式先计算出所有长度为2、3、...、n的子问题的解,然后再利用这些子问题的解来递推计
算整个问题的解,这就是动态规划的思想。
总结起来,石子合并问题的原理就是使用动态规划,通过定义状态和状态转移方程,逐步递推计算出最终的结果。
[动态规划]石子合并问题
[动态规划]⽯⼦合并问题https:///onlinejudge2/index.php/Home/Contest/contestproblem/cid/3016/pid/1729⽯⼦合并问题Time Limit: 1000 ms Memory Limit: 65536 KiBProblem Description在⼀个圆形操场的四周摆放着n堆⽯⼦。
现要将⽯⼦有次序地合并成⼀堆。
规定每次只能选相邻的2 堆⽯⼦合并成新的⼀堆,并将新的⼀堆⽯⼦数记为该次合并的得分。
试设计⼀个算法,计算出将n堆⽯⼦合并成⼀堆的最⼩得分和最⼤得分。
对于给定n堆⽯⼦,计算合并成⼀堆的最⼩得分和最⼤得分。
Input输⼊数据的第1⾏是正整数n,1≤n≤100,表⽰有n堆⽯⼦。
第⼆⾏有n个数,分别表⽰每堆⽯⼦的个数。
Output输出数据有两⾏,第1⾏中的数是最⼩得分,第2⾏中的数是最⼤得分。
Sample Input44 45 9Sample Output4354算法考试考完了(题⽬有点简单侥幸AK..),但这个问题当时困扰我了很久,⽹上解答的很模糊,因此还是在这⾥记录⼀下吧。
这题的难点是:如果将环形转换为直线(直线的⽹上有很多解答,这⾥不做赘述)。
其核⼼思想就是:通过将数量变为 2n-1 来转换成直线问题。
当时看到这⼏⾏字困惑了很久,⼀直不太理解,但之后画图就懂了。
1. 我们为了将环形变为直线,必须规定转动顺序,这⾥采⽤逆时针转动,且以 i 作为起点,j作为终点。
(右下图)2. 当规定好终点了,那么这环形有4种情况,我们求在这四种情况下最下的。
(右上图)3. 关于转换成直线,⽐如存在 a(0) -> b(1) -> c(2) -> d(3) 与 d(3) -> a(4) -> b(5) -> c(6)。
第⼀条是 i=0,j=3的数组,第⼆条是 i=3,j=6 的数组。
这样,我们就不⽤返回去计算了( 3->0->1->2 )。
石子合并问题(直线版)
⽯⼦合并问题(直线版)⽬录题⽬:⽯⼦合并(⼀)时间限制:1000 ms | 内存限制:65535 KB难度:3描述有N堆⽯⼦排成⼀排,每堆⽯⼦有⼀定的数量。
现要将N堆⽯⼦并成为⼀堆。
合并的过程只能每次将相邻的两堆⽯⼦堆成⼀堆,每次合并花费的代价为这两堆⽯⼦的和,经过N-1次合并后成为⼀堆。
求出总的代价最⼩值。
输⼊有多组测试数据,输⼊到⽂件结束。
每组测试数据第⼀⾏有⼀个整数n,表⽰有n堆⽯⼦。
接下来的⼀⾏有n(0< n <200)个数,分别表⽰这n堆⽯⼦的数⽬,⽤空格隔开输出输出总代价的最⼩值,占单独的⼀⾏样例输⼊31 2 3713 7 8 16 21 4 18样例输出9239最普通的算法O(n^3):1 #include <fstream>2 #include <iostream>3 #include <cstdio>4 #include <cstring>5 #include <cstdlib>6 #include <cmath>7using namespace std;89const int N=205;10const int INF=0x7fffffff;11int n;12int a[N],sum[N],dp[N][N];1314void f();1516int main(){17//freopen("D:\\input.in","r",stdin);18while(~scanf("%d",&n)){19 sum[0]=0;20for(int i=1;i<=n;i++){21 scanf("%d",&a[i]);22 sum[i]=sum[i-1]+a[i];23 }24 f();25 printf("%d\n",dp[1][n]);26 }27return0;28}29void f(){30for(int i=1;i<=n;i++) dp[i][i]=0;31for(int r=1;r<n;r++){32for(int i=1;i<n;i++){33int j=i+r;34if(j>n) break;35 dp[i][j]=INF;36for(int k=i;k<=j;k++){37 dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]);38 }39 dp[i][j]+=sum[j]-sum[i-1];40 }41 }42 }224ms其中,dp[i][j]代表i到j堆的最优值,sum[i]代表第1堆到第i堆的数⽬总和。
动态规划中的石子归并问题
动态规划中的⽯⼦归并问题⼀.有N堆⽯⼦,每堆的重量是w[i],可以任意选两堆合并,每次合并的花费为w[i]+w[j],问把所有⽯⼦合并成为⼀堆后的最⼩花费是多少。
因为是可以任意合并,所以每次合并的时候选最⼩的两堆合并,贪⼼即可。
⼆.有N堆⽯⼦,每堆的重量是a[i],排成⼀条直线,每次只能合并相邻的两堆,直到合成⼀堆为⽌,问最后的最⼩花费是多少。
分析:因为规定了只能合并相邻的两堆,显然不能使⽤贪⼼法。
分成⼦问题来考虑,定义dp[i][j]表⽰从第i的⽯⼦合并到第j个⽯⼦的最⼩花费,那么dp[1][N]就是问题的解。
可以推出dp[i][j] = min(dp[i][k]+dp[k+1][j]) k∈(i,j)初始时dp[i][j] = INF(i!=j) dp[i][i] = INF1 #include <iostream>2 #include <cstring>3 #include <cstdio>4 #include <string>5 #include <algorithm>6using namespace std;7int T, n;8int a[210], dp[210][210], sum[210], s[210][210];9//这⾥是数据量⽐较⼩10int INF = 99999999;11int main(){12while(scanf("%d", &n) != EOF){13 memset(sum, 0, sizeof(sum));14for(int i = 1; i <= n; i++){15 cin>>a[i];16 sum[i] = sum[i-1] + a[i];17 }18for(int i = 1; i <= n; i++){19for(int j = 1; j <= n; j++)20 dp[i][j] = INF;21 }22for(int i = 1; i <= n; i++) dp[i][i] = 0;2324for(int len = 2; len <= n; len++){ //表⽰归并的长度25for(int i = 1; i <= n-len+1; i++){ //归并的第⼀位26int j = i+len-1; //归并的最后⼀位27for(int k = i; k < j; k++){28 dp[i][j] = min(dp[i][j], dp[i][k] + dp[k+1][j] + sum[j] - sum[i-1]);29 }30 }31 }32 cout<<dp[1][n]<<endl;33 }34return0;35 }这样复杂度是O(N^3)可以利⽤四边形不等式优化到O(N^2)四边形不等式:如果对于任意的a≤b≤c≤d,有m[a,c] + m[b,d] <= m[a,d] + m[b,c]那么m[i,j]满⾜四边形不等式。
动态规划-石子合并
目录
• 问题描述与背景 • 动态规划基础 • 石子合并问题动态规划解法 • 案例分析与实践 • 拓展应用与变体问题 • 总结与展望
问题描述与背景
01
石子合并问题介绍
问题描述
给定一个由正整数组成的环形数组,表示一堆环形排列的石子。每次操作可以选 择相邻的两堆石子进行合并,合并的代价为两堆石子的重量之和。求将所有石子 合并为一堆的最小代价。
算法性能评估与比较
时间复杂度分析
空间复杂度分析
动态规划算法的时间复杂度通常为 O(n^3),其中n为石子的堆数。这是 因为需要枚举所有可能的区间和断点, 并进行状态转移。对于较大的n,可能 需要优化算法以降低时间复杂度。
动态规划算法的空间复杂度通常为 O(n^2),其中n为石子的堆数。这是 因为需要使用一个二维数组来存储状 态转移的结果。可以通过滚动数组等 技巧优化空间复杂度。
与其他算法的比较
除了动态规划算法外,还可以使用贪 心算法、分治算法等来解决石子合并 问题。贪心算法通常具有较低的时间 复杂度,但可能无法得到最优解。分 治算法可以将问题分解为多个子问题 分别求解,但可能涉及大量的重复计 算。动态规划算法可以在保证得到最 优解的同时,避免重复计算,问题,且子问题的最优解 可以推出原问题的最优解。
无后效性
某个阶段的状态一旦确定, 则此后过程的发展不受此 前各段状态的影响。
石子合并问题动态规
03
划解法
状态定义与转移方程
状态定义
设 $f[i][ j]$ 表示将第 $i$ 堆到第 $j$ 堆石子合并成一堆的最 小/最大代价。
明确问题的边界条件,即最小子问题的解。
定义状态
为每个子问题定义一个状态,通常用一个数 组或哈希表来存储状态值。
关于石子的研究报告怎么写
关于石子的研究报告怎么写
写一份关于石子的研究报告时,可以按照以下结构进行组织:
1. 引言:
- 简要介绍石子的背景和重要性。
- 阐述研究目的和研究问题。
2. 文献综述:
- 综述现有关于石子的研究,包括相关概念、分类和应用领域。
- 概述已有研究的主要发现和结果。
3. 研究设计与方法:
- 描述研究的方法论框架,包括研究方法和数据来源。
- 解释研究采用的实验、观察、问卷调查等具体方法。
- 说明研究数据的采集、处理和分析方法。
4. 研究结果:
- 对研究数据进行详细的描述和分析。
- 使用适当的图表和统计数据来展示研究结果。
- 对研究结果进行解释和讨论。
5. 结论:
- 总结研究的主要发现和结果,回答研究问题。
- 强调研究的价值和意义。
- 提出研究限制,并对未来进一步研究方向进行建议。
6. 参考文献:
- 列出研究过程中引用的所有参考文献,按照一定的格式规
范进行引用。
提示:
- 在撰写报告时,要确保使用简明清晰的语言表达思想和观点。
- 对于研究结果的解释和讨论,要基于实证数据和现有理论,
进行科学和合理的分析。
- 在报告中使用适当的标题和子标题,以帮助读者更好地理解
报告的结构和内容。
- 最后,进行仔细的校对和编辑,确保报告的语法、拼写和格
式没有错误。
石场整合工作总结
石场整合工作总结
在石场工作中,整合工作是非常重要的一环。
通过整合工作,我们可以更好地
协调各个部门之间的工作,提高生产效率,降低成本,提升产品质量。
在过去的一段时间里,我们团队在石场整合工作方面取得了一些进展,现在让我们来总结一下。
首先,我们在整合工作中注重了沟通和协作。
各个部门之间的沟通是非常重要的,只有通过良好的沟通,才能更好地协调各个部门之间的工作。
我们建立了定期的沟通机制,每周举行一次部门间的会议,交流工作进展和存在的问题,并及时进行协调解决。
同时,我们也建立了跨部门合作的机制,鼓励各个部门之间积极合作,共同完成工作任务。
其次,我们在整合工作中注重了信息共享和资源整合。
我们建立了一个信息平台,将各个部门的信息进行整合,实现了信息的共享和资源的整合。
这样一来,我们可以更好地利用各个部门的资源,提高资源利用效率,降低成本。
同时,也可以更好地了解各个部门的工作情况,及时进行调整和协调。
最后,我们在整合工作中注重了团队建设和人才培养。
我们重视团队建设,建
立了一个和谐的团队氛围,鼓励员工之间相互合作,共同进步。
同时,我们也注重人才培养,定期组织培训和学习,提高员工的综合素质和专业技能,为整合工作提供了有力的保障。
总的来说,石场整合工作是一个复杂而又重要的工作,需要各个部门之间的密
切合作和协调。
我们团队在整合工作方面取得了一些成绩,但也存在一些问题和不足。
希望在今后的工作中,我们可以进一步加强整合工作,提高工作效率,提升产品质量,为石场的发展做出更大的贡献。
2023年大理石矿权整合情况汇报
⽯⼦合并问题--任意版有N堆⽯⼦,现要将⽯⼦有序的合并成⼀堆,规定如下:每次只能移动任意的2堆⽯⼦合并,合并花费为将的⼀堆⽯⼦的数量。
设计⼀个算法,将这N堆⽯⼦合并成⼀堆的总花费最⼩(或最⼤)。
此类问题⽐较简单,就是哈夫曼编码的变形,⽤贪⼼算法即可求得最优解。
即每次选两堆最少的,合并成新的⼀堆,直到只剩⼀堆为⽌。
证明过程可以参考哈夫曼的证明过程。
代码如下:#include <iostream>#include <fstream>#include <deque>#include <algorithm>using namespace std;struct Node{int key;Node* left;Node* right;Node(){left=0;right=0;}};deque<Node*>forest;ifstream fin("in.txt");static int min = 0;bool compare(Node* a,Node* b){return a->key < b->key; //求最⼩组合//return a->key > b->key; //求最⼤组合}void print(Node *head){if(head->left){cout<<head->key<<" ";print(head->left);print(head->right);min=min+head->key;}return;}int main(){int n;fin>>n;Node *p;for(int i=0;i<n;i++){p=new Node;fin>>p->key;forest.push_back(p);}/* //反向迭代器逆序输出也可⽤来求最⼤值deque<Node*>::reverse_iterator rit;rit = forest.rbegin();for(i=0;i<n;i++){cout<<" - "<<rit[i]->key<<endl;}*/for(i=0;(i<n) && (forest.size()>1);i++){sort(forest.begin(),forest.end(),compare);p = new Node;p->key = forest[0]->key + forest[1]->key;p->left = forest[0];p->right = forest[1];forest.pop_front();forest.pop_front();forest.push_back(p);}p = forest.front();print(p);cout<<endl<<"min:"<<min<<endl;return 0;}输⼊⽂件: in.txt 102 4 5 6 4 103 6 8 1输出结果:49 21 11 28 12 6 3 16 8 min:154Press any key to continue。
大理石矿权整合情况汇报
大理石矿权整合情况汇报尊敬的领导:根据您的要求,我对大理石矿权整合情况进行了汇报。
以下是我对大理石矿权整合情况的详细分析和总结。
一、整合背景大理石是一种广泛应用于建筑、装饰、雕塑等领域的高质量石材,具有质地坚硬、表面光滑、纹理美观等特点,市场需求量巨大。
然而,在矿权分散和管理乱象的情况下,部分大理石矿区的开采效果受到了限制,资源浪费严重。
因此,整合大理石矿权具有重要的意义。
二、整合目标1. 提高大理石矿区的开采效果和资源利用率:通过整合,合理规划矿区,避免重复开采和资源浪费,减少环境污染,提高利用效率。
2. 健全大理石矿权管理机制:建立统一的矿权管理体系,完善相关法规和政策,规范矿权拍卖、交易等运作流程,保障矿产资源的可持续发展。
3. 提高行业竞争力:整合后的大理石矿权管理体系将有助于推动企业间的竞争与合作,提高行业整体竞争力,并对国内外市场产生积极影响。
三、整合方式大理石矿权整合主要通过以下几种方式进行:1. 通过政府引导,推动矿权合作。
政府通过规划和政策引导,鼓励大理石矿权持有方进行自愿合作,共同打造大理石矿业联盟,形成资源整合、市场竞争力提升的合作模式。
2. 采取矿权拍卖和交易等市场化方式。
政府可以通过拍卖或交易等市场化方式,将零散的大理石矿权进行整合,使其流转到合适的拥有者手中,并规范矿权管理流程。
3. 促进跨地区合作。
在大理石矿权整合的过程中,可以鼓励矿区之间进行合作与交流,共同开发利用跨地区的大理石矿产资源,实现资源优势互补。
四、整合效果及问题1. 整合效果通过大理石矿权整合,可以实现资源的合理集中,有效规避资源浪费和环境破坏的问题。
整合后的大理石矿区能够更好地满足市场需求,提高利用效率和开采效果,推动行业的快速发展。
2. 存在问题在整合过程中,也存在一些问题,主要包括:(1)权益分配问题:由于各方对矿权的评估不一致,存在权益分配的争议。
应加强协商和沟通,寻求各方的共识,并确保合理的权益分配。
石子合并问题--任意版
⽯⼦合并问题--任意版有N堆⽯⼦,现要将⽯⼦有序的合并成⼀堆,规定如下:每次只能移动任意的2堆⽯⼦合并,合并花费为将的⼀堆⽯⼦的数量。
设计⼀个算法,将这N堆⽯⼦合并成⼀堆的总花费最⼩(或最⼤)。
此类问题⽐较简单,就是哈夫曼编码的变形,⽤贪⼼算法即可求得最优解。
即每次选两堆最少的,合并成新的⼀堆,直到只剩⼀堆为⽌。
证明过程可以参考哈夫曼的证明过程。
代码如下:#include <iostream>#include <fstream>#include <deque>#include <algorithm>using namespace std;struct Node{int key;Node* left;Node* right;Node(){left=0;right=0;}};deque<Node*>forest;ifstream fin("in.txt");static int min = 0;bool compare(Node* a,Node* b){return a->key < b->key; //求最⼩组合//return a->key > b->key; //求最⼤组合}void print(Node *head){if(head->left){cout<<head->key<<" ";print(head->left);print(head->right);min=min+head->key;}return;}int main(){int n;fin>>n;Node *p;for(int i=0;i<n;i++){p=new Node;fin>>p->key;forest.push_back(p);}/* //反向迭代器逆序输出也可⽤来求最⼤值deque<Node*>::reverse_iterator rit;rit = forest.rbegin();for(i=0;i<n;i++){cout<<" - "<<rit[i]->key<<endl;}*/for(i=0;(i<n) && (forest.size()>1);i++){sort(forest.begin(),forest.end(),compare);p = new Node;p->key = forest[0]->key + forest[1]->key;p->left = forest[0];p->right = forest[1];forest.pop_front();forest.pop_front();forest.push_back(p);}p = forest.front();print(p);cout<<endl<<"min:"<<min<<endl;return 0;}输⼊⽂件: in.txt 102 4 5 6 4 103 6 8 1输出结果:49 21 11 28 12 6 3 16 8 min:154Press any key to continue。
乡镇山石资源综合整治工作汇报
20XX年乡镇山石资源综合整治工作汇报自开展全区山石资源综合整治工作以来,我镇严格按照区委、区政府、区指挥部的要求扎实开展山石资源综合整治工作,目前已取得明显实效。
现将近期开展的工作汇报如下:一、目前完成的工作一是积极实行包保制度。
每名副科级以上干部包保1--2家采石企业,督促企业按照标准要求进行整改,在每半月召开一次领导干部会议上,加强调度,了解全镇山石企业的整改进展。
二是以点带面整体推进。
在区国土局的帮助下,从全镇范围内筛选出进展快,效果明显的3家企业作为典型,严格按照整改标准认真落实,从而为其他山石企业的提供了模板,推进了全镇的整改进程。
三是严格标准进行整改。
为确保山石整治效果,5月30日,镇山石指挥部组织环保、国土、供电、安监等部门对8家企业进行了初验,并严格按照区下发的整治标准提出了整改意见。
6月初,又集中两天时间邀请区指挥部进行了复验,目前,8家企业均已通过验收。
在此次山石整治活动中,各山石企业加大投入,已整改的企业都设立了界桩,安装了铁丝网,并按照“平厢盖布”要求,加强对道路脱落扬撒工作的治理。
截至目前共新上吸尘设备20台,设立防尘网12道,打深井10眼。
另有4家正在整改,待整改完成后提出验收申请。
二、存在的问题与不足一是个别企业思想认识程度不够,没有意识到此次综合整治活动的重要性和严肃性,整改的积极性不高,主动性不强,存有等、看、靠的思想,到目前为止还有3家企业没有进行整改。
二是部分企业行动迟缓、执行不力。
主要表现在未按照指挥部下发的整改标准、要求进行及时整改,整改速度较慢,整改效果不明显。
三、两点建议:一是石子在运输过程中石子洒落问题难以控制,由于各运输车辆大部分都是改装车辆,私自加高厢板,即使平厢装货也难以控制石子的洒落,镇上的执法和监督力度有限。
二是税收征缴存在一定困难。
采石企业平均每3天左右就要放一次炸药,镇地税所无权开具税票,每次都要到区服务大厅缴纳税费,增加了成本,能否协调国地税在乡镇专门设立税费征收窗口。
矿山整合汇报方案
矿山整合汇报方案背景随着矿山规模的扩大以及市场竞争的加剧,矿山企业之间的合并和整合愈发普遍。
矿山整合不仅可以实现资源优化配置,提高企业效益,而且有助于缓解环境压力,降低矿山开采对自然环境的影响。
本文旨在探讨矿山整合的目的、面临的挑战以及整合汇报方案。
目的矿山整合的目的是使矿山企业之间资源、技术、市场等方面的互补性得到发挥,从而优化资源配置,提高企业效益,并在可持续发展的基础上降低开采对自然环境的负面影响。
面临的挑战虽然矿山整合有诸多优点,但实施过程中也存在一些难题:1.土地、环境等方面的冲突。
矿山整合往往需要一定的土地才能完成,但这可能会导致一定程度的土地使用冲突。
另外,矿山整合后,可能会导致环境污染和生态破坏等问题。
2.资源分配问题。
资源的统一分配可能会引发各方的不满和矛盾。
特别是涉及到土地、矿产等资源的分配时,更容易引起争议。
3.管理集成问题。
如何对不同企业的管理进行整合,避免出现重复建设和浪费资源的情况,是一个重要的问题。
整合汇报方案为了解决矿山整合过程中的难题,我们提出以下整合汇报方案:1. 统一咨询在整合过程中,应该设立专门的咨询机构,来统一规划和协调各方面工作。
同时,咨询机构也可以为整合双方提供咨询和媒介服务,帮助双方协商解决问题。
2. 共享资源在整合过程中,每家企业都应该对自己的资源进行清单登记,并对整合过程中需要共享的资源进行明确划分,并设立专门机构来管理共享资源。
这样,可以避免资源重叠和浪费,提高资源的利用效率。
3. 统一劳动力管理整合企业在工作人员管理上也应做出相应的调整。
由于原企业之间人员性质不同,管理体系不同,管理方案也应有所调整和整合。
可以考虑采用一体化管理制度,或设立专门的人力资源部门,来统一管理人力资源。
4. 共同研发在技术方面,各方应该进行资源共享和技术交流,鼓励申请协同研发项目。
这有助于提高企业的技术创新能力和核心竞争力。
5. 共享风险在整合过程中,可能会需要共享风险。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
石子合并(动态规划)详细解题报告2007-02-25 14:58一.试题在一个园形操场的四周摆放N堆石子(N≤100),现要将石子有次序地合并成一堆。
规定每次只能选相邻的两堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
编一程序,由文件读入堆数N及每堆的石子数(≤20),①选择一种合并石子的方案,使得做N-1次合并,得分的总和最小;②选择一种合并石子的方案,使得做N-1次合并,得分的总和最大。
例如,所示的4堆石子,每堆石子数(从最上面的一堆数起,顺时针数)依次为4594。
则3次合并得分总和最小的方案:8+13+22=43得分最大的方案为:14+18+22=54输入数据:文件名由键盘输入,该文件内容为:第一行为石子堆数N;第二行为每堆的石子数,每两个数之间用一个空格符分隔。
输出数据:输出文件名为output.txt从第1至第N行为得分最小的合并方案。
第N+1行是空行。
从第N+2行到第2N+1行是得分最大合并方案。
每种合并方案用N行表示,其中第i行(1≤i≤N)表示第i 次合并前各堆的石子数(依顺时针次序输出,哪一堆先输出均可)。
要求将待合并的两堆石子数以相应的负数表示,以便标识。
输入输出范例:输入文件内容:44594输出文件内容:-459-4-8-59-13-9224-5-944-14-4-4-1822二.算法分析竞赛中多数选手都不约而同地采用了尽可能逼近目标的贪心法来逐次合并:从最上面的一堆开始,沿顺时针方向排成一个序列。
第一次选得分最小(最大)的相邻两堆合并,形成新的一堆;接下来,在N-1堆中选得分最小(最大)的相邻两堆合并……,依次类推,直至所有石子经N-1次合并后形成一堆。
例如有6堆石子,每堆石子数(从最上面一堆数起,顺时针数)依次为346542要求选择一种合并石子的方案,使得做5次合并,得分的总和最小。
按照贪心法,合并的过程如下:每次合并得分第一次合并346542 ->5第二次合并54654 ->9第三次合并9654 ->9第四次合并969 ->15第五次合并159 ->2424总得分=5+9+9+15+24=62但是当我们仔细琢磨后,可得出另一个合并石子的方案:每次合并得分第一次合并346542 ->7第二次合并76542 ->13第三次合并13542 ->6第四次合并1356 ->11第五次合并1311 ->2424总得分=7+6+11+13+24=61显然,后者比贪心法得出的合并方案更优。
题目中的示例故意造成一个贪心法解题的假像,诱使读者进入“陷阱”。
为了帮助读者从这个“陷阱”里走出来,我们先来明确一个问题:1.最佳合并过程符合最佳原理使用贪心法至所以可能出错,是因为每一次选择得分最小(最大)的相邻两堆合并,不一定保证余下的合并过程能导致最优解。
聪明的读者马上会想到一种理想的假设:如果N-的全局最优解包含了每一次合并的子问题的最优解,那么经这样的N-1次合并后的得分总和必然是最优的。
例如上例中第五次合并石子数分别为13和11的相邻两堆。
这两堆石头分别由最初的第1,2,3堆(石头数分别为3,4,6)和第4,5,6堆(石头数分别为5,4,2)经4次合并后形成的。
于是问为如何使得这两个子序列的N-2次合并的得分总和最优。
为了实现这一目标,我们将第1个序列又一分为二:第1、2堆构成子序列1,第3堆为子序列2。
第一次合并子序列1中的两堆,得分7;第二次再将之与子序列2的一堆合并,得分13。
显然对于第1个子序列来说,这样的合并方案是最优的。
同样,我们将第2个子序列也一分为二;子序列1,第5,6堆构成子序列2。
第三次合并子序列2中的2堆,得分6;第四次再将之与子序列1中的一堆合并,得分13。
显然对于第二个子序列来说合并方案也是最优的。
由此得出一个结论──6堆石子经过这样的5次合并后,得分的总和最小。
我们把每一次合并划分为阶段,当前阶段中计算出的得分和作为状态,如何在前一次合并的基础上定义一个能使目前得分总和最大的合并方案作为一次决策。
很显然,某阶段的状态给定后,则以后各阶段的决策不受这阶段状态的影响。
这种无后效性的性质符最佳原理,因此可以用动态规划的算法求解。
2.动态规划的方向和初值的设定采用动态规划求解的关键是确定所有石子堆子序列的最佳合并方案。
这些石子堆子序列包括:{第1堆、第2堆}、{第2堆、第3堆}、……、{第N堆、第1堆};{第1堆、第2堆、第3堆}、{第2堆、第3堆、第4堆}、……、{第N堆、第1堆、第2堆};……{第1堆、……、第N堆}{第2堆、……、第N堆、第1堆}……{第N堆、第1堆、……、第N-1堆}为了便于运算,我们用〔i,j〕表示一个从第i堆数起,顺时针数j堆时的子序列{第i堆、第i+1堆、……、第(i+j-1)mod n堆}它的最佳合并方案包括两个信息:①在该子序列的各堆石子合并成一堆的过程中,各次合并得分的总和;②形成最佳得分和的子序列1和子序列2。
由于两个子序列是相邻的,因此只需记住子序列1的堆数;设f〔i,j〕──将子序列〔i,j〕中的j堆石子合并成一堆的最佳得分和;c〔i,j〕──将〔i,j〕一分为二,其中子序列1的堆数;(1≤i≤N,1≤j≤N)显然,对每一堆石子来说,它的f〔i,1〕=0c〔i,1〕=0(1≤i≤N)对于子序列〔i,j〕来说,若求最小得分总和,f〔i,j〕的初始值为∞;若求最大得分总和,f〔i,j〕的初始值为0。
(1≤i≤N,2≤j≤N)动态规划的方向是顺推(即从上而下)。
先考虑含二堆石子的N个子序列(各子序列分别从第1堆、第2堆、……、第N堆数起,顺时针数2堆)的合 f〔1,2〕,f〔2,2〕,……,f〔N,2〕c〔1,2〕,c〔2,2〕,……,c〔N,2〕然后考虑含三堆石子的N个子序列(各子序列分别从第1堆、第2堆、……、第N堆数起,顺时针数3堆)的合并方案f〔1,3〕,f〔2,3〕,……,f〔N,3〕c〔1,3〕,c〔2,3〕,……,c〔N,3〕……依次类推,直至考虑了含N堆石子的N个子序列(各子序列分别从第1堆、第2堆、……、第N堆数起,顺时针数N堆)的合并方案f〔1,N〕,f〔2,N〕,……,f〔N,N〕c〔1,N〕,c〔2,N〕,……,c〔N,N〕最后,在子序列〔1,N〕,〔2,N〕,……,〔N,N〕中,选择得分总和(f值)最小(或最大)的一个子序列〔i,N〕(1≤i≤N),由此出发过程。
3.动态规划方程和倒推合并过程对子序列〔i,j〕最后一次合并,其得分为第i堆数起,顺时针数j堆的石子总数t。
被合并的两堆石子是由子序列〔i,k〕和〔(i+k-1)mod n+1,j-k〕(1≤k≤j-1)经有限次合并形成的。
为了求出最佳合并方案中的k值,我们定义一个动态规划方程:当求最大得分总和时f〔i,j〕=max{f〔i,k〕+f〔x,j-k〕+t}1≤k≤j-1c〔i,j〕=k│ f〔i,j〕=f〔i,k〕+f〔x,j-k〕+t(2≤j≤n,1≤i≤n)当求最小得分总和时f〔i,j〕=min{f〔i,k〕+f〔x,j-k〕+t}1≤k≤j-1c〔i,j〕=k│ f〔i,j〕=f〔i,k〕+f〔x,j-k〕+t(2≤j≤n,1≤i≤n)其中x=(i+k-1)modn+1,即第i堆数起,顺时针数k+1堆的堆序号。
例如对上面例子中的6(346542 )堆石子,按动态规划方程顺推最小得分和。
依次得出含二堆石子的6个子序列的合并方案 f〔1,2〕=7 f〔2,2〕=10 f〔3,2〕=11c〔1,2〕=1 c〔2,2〕=1 c〔3,2〕=1f〔4,2〕=9 f〔5,2〕=6 f〔6,2〕=5c〔4,2〕=1 c〔5,2〕=1 c〔6,2〕=1含三堆石子的6(346542 )个子序列的合并方案f〔1,3〕=20 f〔2,3〕=25 f〔3,3〕=24c〔1,3〕=2 c〔2,3〕=2 c〔3,3〕=1f〔4,3〕=17 f〔5,3〕=14 f〔6,3〕=14c〔4,3〕=1 c〔5,3〕=1 c〔6,3〕=2含四堆石子的6(346542 )个子序列的合并方案f〔1,4〕=36 f〔2,4〕=38 f〔3,4〕=34c〔1,4〕=2 c〔2,4〕=2 c〔3,4〕=1f〔4,4〕=28 f〔5,4〕=26 f〔6,4〕=29c〔4,4〕=1 c〔5,4〕=2 c〔6,4〕=3含五堆石子的6(346542 )个子序列的合并方案f〔1,5〕=51 f〔2,5〕=48 f〔3,5〕=45c〔1,5〕=3 c〔2,5〕=2 c〔3,5〕=2f〔4,5〕=41 f〔5,5〕=43 f〔6,5〕=45c〔4,5〕=2 c〔5,5〕=3 c〔6,5〕=3含六堆石子的6(346542 )个子序列的合并方案f〔1,6〕=61 f〔2,6〕=62 f〔3,6〕=61c〔1,6〕=3 c〔2,6〕=2 c〔3,6〕=2f〔4,6〕=61 f〔5,6〕=61 f〔6,6〕=62c〔4,6〕=3 c〔5,6〕=4 c〔6,6〕=3f〔1,6〕是f〔1,6〕,f〔2,6〕,……f〔6,6〕中的最小值,表明最小得分和是由序列〔1,6〕经5次合并得出的。
我们从这个序按下述方法倒推合并过程:由c〔1,6〕=3可知,第5次合并的两堆石子分别由子序列〔1,3〕和子序列〔4,3〕经4次合并后得出。
其中c〔1,3〕=2可知由子序3〕合并成的一堆石子是由子序列〔1,2〕和第三堆合并而来的。
而c〔1,2〕=1,以表明了子序列〔1,2〕的合并方案是第1堆合并第2堆。
由此倒推回去,得出第1,第2次合并的方案,每次合并得分第一次合并346…… ->7第二次合并76…… ->1313……子序列〔1,3〕经2次合并后合并成1堆,2次合并的得分和=7+13=20。
c〔4,3〕=1,可知由子序列〔4,3〕合并成的一堆石子是由第4堆和子序列〔5,2〕合并而来的。
而c〔5,2〕=1,又表明了子序列〔5,2〕的合并方案是第5堆合并第6堆。
由此倒推回去,得出第3、第4次合并的方案每次合并得分:第三次合并……542 ->6第四次合并……56 ->11……11子序列〔4,3〕经2次合并后合并成1堆,2次合并的得分和=6+11=17。
第五次合并是将最后两堆合并成1堆,该次合并的得分为24。
显然,上述5次合并的得分总和为最小20+17+24=61上述倒推过程,可由一个print(〔子序列〕)的递归算法描述procedure print (〔i,j〕)beginif j〈〉1 then {继续倒推合并过程beginprint(〔i,c〔i,j〕〕;{倒推子序列1的合并过程}print(〔i+c〔i,j〕-1〕mod n+1,j-c〔i,j〕){倒推子序列2的合并过程}for K:=1 to N do{输出当前被合并的两堆石子}if (第K堆石子未从圈内去除)then beginif(K=i)or(K=X)then置第K堆石子待合并标志else第K堆石子未被合并;end;{then}第i堆石子数←第i堆石子数+第X堆石子数;将第X堆石子从圈内去除;end;{then}end;{print}例如,调用print(〔1,6〕)后的结果如下:print(〔1,6〕)⑤┌──────┴──────┐print(〔1,3〕)② print(〔4,3〕)④┌─────┴─────┐┌─────┴─────┐ print(〔1,2〕)① print(〔3,1〕) print(〔4,1〕) print(〔5,2〕)③┌──────┴──────┐┌──────┴──────┐ print(〔1,1〕) print(〔2,1〕) print(〔5,1〕)print(〔6,1〕)(图6.2-5)其中回溯至① 显示34654② 显示76542③ 显示13542④ 显示1356⑤ 显示1311注:调用print过程后,应显示6堆石子的总数作为第5次合并的得分。