动态规划之合并石子

本文介绍了动态规划的概念,并通过合并石子的问题详细解析了如何使用C语言解决动态规划问题。文章首先阐述动态规划的定义,然后分析合并石子的思路,最后展示具体代码实现。动态规划通过将大问题分解为小问题,通过状态转移找到最优解,文中通过实例展示了如何计算合并石子的最小得分。
摘要由CSDN通过智能技术生成

动态规划——合并石子(C语言解)

第一次接触到动态规划是在斐波那契数列,那个时候还不知道动态规划的概念,由于数据量较小,直接用for循环就通过了,直到遇到了”合并石子“这道题目,百度过很多的文章都没看懂,大佬们都讲得太抽象了,一上来就是状态改变方程,算法小白一脸懵逼。经过一段时间的理解我终于搞懂了这道题目,下面说一说我的解法(可能不是最佳解法),希望能帮到大家。

动态规划的概念

首先我们要搞懂什么是动态规划。我觉得动态规划就是把一个大问题分解为多个小问题,每个小问题的决策都会影响到下一个小问题的决策。(下一个小问题的决策就是由上一个小问题的决策而产生的。)一个状态经过一个决策变成了另外一个状态,这个过程就是状态转移,用来描述状态转移的方程就是状态转移方程。

题目和思路

在一个操场上一排地摆放着N堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。请设计一个程序,计算出将N堆石子合并成一堆的最小得分。

我们首先来分析一个比较简单的问题,现在一共有三堆石头,每堆石子的数量分别是3,4,11。求合并成一堆石头的最小得分。
对于这个问题,只有两种选择:
前两堆石头合并再和第三堆石头合并。
3+4=7 ——> 7 石堆变为(7, 11)
7+11=18——>18 石堆变为(18)
cost=7+18=25
后两堆石头合并再和第一堆石头合并。
4+11=15——>15 石堆变为(3,15)
3+15=18——>18 石堆变为(18)
cost=15+18=33

易看出先合并前两堆的石子的花费比较小,不同的合并方式会造成不同的得分。同时可以发现这两种方法最后一次的得分就是石头的总数。
现在我们用一个数组arr[]按顺序保存每个位置的石头数量。
arr[]={3,4,11}

二维数组sum[i][j]表示第i堆石头到第j堆石头的总和
sum[0][1]=3+4=7;
sum[1][2]=4+11=15;
sum[0][2]=3+4+11=18;

最后用一个二维数组dp[i][j]表示从第i堆到第j堆石头合并的最小分数。
1)每堆石头跟自己合并的分数都是0。
dp[0][0]=dp[1][1]=dp[2][2]=0
2)相邻两堆石头的最小合并分数只有一种可能。
dp[0][1]=3+4=7, dp[1][2]=4+11=15
3)剩下的就是不相邻石头的合并最小花费。
设一个k∈[i,j];
dp[i][j]=dp[i][k]+dp[k][j]+sum[i][j];
那么从i到j的所有花费都可以表示出来了,取一个使得dp[i][j]最小的值。
我们用表格来表示出从i到j的费用最小值。(对于C来说一般是序号从0开始)
在这里插入图片描述
dp[1][3]=min(dp[1][1]+dp[2][3] , dp[1][2]+dp[3][3])+sum[1][3];
dp[2][4]=min(dp[2][3]+dp[4][4] , dp[2][2]+dp[3][4])+sum[2][4];
dp[1][4]=min(dp[1][1]+dp[2][4],dp[1][2]+dp[3][4],dp[1][3]+dp[4][4])+sum[1][4];
我们最终的目的是求出dp[1][4],那我们就要先求出dp[1][3]和dp[2][4],从图像上我们要求最右上角的值,就是沿着副对角线一步步往上求。
在这里插入图片描述
思路就是这样了,下面是代码。

具体代码

#include <stdio.h>
int main()
{
   
    int n,i,j,t,a,b
  • 100
    点赞
  • 238
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
做如下两个模型的石子合并,如下模型石子都不能移动出列,且合并都仅发生在相邻两石子中: (1)第一个模型:一行排列且相邻合并 有n石子一行(a1,a2,…,an,ai为第i石子个数),相邻两合并合并的分值为新石子数。求合并一堆的最低得分和最高得分。 (2)第二个模型:一圈排列且相邻合并 有n石子首位相连的一个环形(a1,a2,…,an,ai为第i石子个数,an和a1相邻),相邻两合并合并的分值为新石子数。求合并一堆的最低得分和最高得分。 例如4石子,每石子个数:9 4 4 5 若排一行,最小分值:(4+4)+(8+5)+(9+13)=43,最大分值:(9+4)+(13+4)+(17+5)=52。 若排圈状,最小分值:(4+4)+(8+5)+(9+13)=43,最大分值:(9+5)+(14+4)+(18+4)=54。 此题以第一模型的最低得分为例,很多同学想着采用总是从最小的相邻两下手的思想,最后获得的也就是最低得分。但这个贪心策略是不对的。 如下反例: 石子:9 4 6 1 5 贪心策略: 9 4 6 6 6 9 10 6 10 9 16 16 25 25 得分共计:6+10+16+25=57 但9 4 6 1 5 若如下方式合并: 13 6 1 5 13 13 6 6 6 13 12 12 25 25 13+6+12+25=56 或 9 4 6 6 6 9 4 12 12 13 12 13 25 25 6+12+13+25=56 后两种方式合并出的56都比贪心策略的57来的更低,因为总选择最小的相邻两合并,并不能保证后续每步都可以最小,也许这轮最小导致后续几轮分值较大。 Input 两行。第一行n,第二行a1 a2 … an,每个ai(1<=i<=n)表示第i石子的个数,n<=100 Output 两行。第一行是第一个模型的最低得分和最高得分,中间空格相连,第二行是第二个模型的最低得分和最高得分,中间空格相连。 Sample Input 4 9 4 4 5 Sample Output 43 52 43 54 Hint 第一个石子合并模型,和书上3.1节的矩阵连乘问题类似. 假设m[i,j]为合并石子ai…aj, 1≤i≤j≤n,所得到的最小得分,若没有“合并”这个动作,则为0。原问题所求的合并最小值即为m[1,n]。 递推公式如下,其中min表示求最小,sum表示求和. (1) m[i,j]=0, if i=j (2) m[i,j]=min{m[i,k]+m[k+1][j] | for i<=k<j} + sum{a(t) | for i<=t<=j}, if i<j 至于求最大值完全同理. 至于第二个石子合并的环行模型,完全可以转化为第一个模型来求解.
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值