动态规划--最小总和问题

今天又学习了一道使用动态规划解决的问题:数塔最小总和问题

题目是这样的:将正整数排成等边三角形,三角形的底边有n个数,下图给出了n=4的一个例子。从三角形顶点出发通过一系列相邻整数(在图中用圆圈表示),如何使得到达底边时的总和最小?为这个问题设计一个动态规划算法。

n=4时的例子:
n=4时的例子
我们可以这样考虑这个问题
从第一层开始,最小值为2
第二层为6
那么第三层呢?
第三层=第二层的动态值加上本身

什么意思呢?
因为总层数为三,所以在第二层时,第二层有两种情况,走2+5等于7的路线或者是2+4=6的路线。即有两个动态值,6和7。
那么第三层的候选值就有7+1=8,7+4=11,6+4=10,6+7=13,因此可以选出8为最小值。
那么继续扩展到第四层就有一个问题,中间为4的那个节点,动态值怎么取,这里我们当然要取最小值,即10;

那么对于第四层,上一层的三个候选值就分别为8,10,13
那么到第四层加上自己本身,就可以得出最小值为8+6 = 14;

所以,我们用f【i】【j】来表示,第i层第j个数字的动态累加值。起始时先将所有边缘和非结点的值置无穷大,然后再运算,示例代码如下:

#include<iostream> 
using namespace std;
int main() 
{ 
 int f[101][101] = { 0 }; 
 int n = 0; 
 int minData =INT_MAX; 
 cout << "输入三角形底边数目:"; 
 cin >> n; 
 for (int i = 0; i <=n; i++)                      //边缘值置无穷大 
 { 
  f[i][0] = INT_MAX; 
  f[0][i] = INT_MAX; 
 } 
 cout << "输入各节点的数:"<< endl; 
 for(int i=1;i<=n;i++) 
  for (int j = 1; j <= n; j++) 
  { 
   if (j <= i) 
    cin >> f[i][j]; 
   else 
    f[i][j] = INT_MAX; 
  } 
 for (int i = 2; i <= n; i++)                             //求各节点动态规划过程中的值 
 { 
  for (int j = 1; j <=i; j++) 
  { 
   if (f[i - 1][j - 1] < f[i - 1][j]) //找相对最小值
    f[i][j] += f[i - 1][j - 1]; 
   else if (f[i - 1][j - 1] >f[i - 1][j]) //找相对最小值
    f[i][j] += f[i - 1][j]; 
   else if (f[i - 1][j - 1] ==f[i - 1][j]) //找相对最小值
    f[i][j] += f[i - 1][j]; 
   cout << f[i][j] << " "; 
  } 
  cout << endl; 
 } 
 for (int i = 1; i <= n; i++) 
 { 
  if (f[n][i] < minData) 
   minData = f[n][i]; 
 } 
 cout << "到达底边时的最小总和为:" << minData << endl; 
 return 0; 
}

中间找相对最小值的步骤可以使用min函数,节省两行代码。该函数包含在头文件里面,这是运行结果,7 6 那一行开始输出的是f【i】【j】的动态值
在这里插入图片描述

由于我还没有完全学会怎么用转移方程来表示关系,这里就不列转移方程了,怕误导大家。

对于这题有什么不懂的或者是我做错的地方,欢迎在评论区提出!

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值