今天又学习了一道使用动态规划解决的问题:数塔最小总和问题
题目是这样的:将正整数排成等边三角形,三角形的底边有n个数,下图给出了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】的动态值
由于我还没有完全学会怎么用转移方程来表示关系,这里就不列转移方程了,怕误导大家。
对于这题有什么不懂的或者是我做错的地方,欢迎在评论区提出!