问题描述
将正整数排成等边三角形,三角形的底边有n个数。从三角形顶点出发通过一系列相邻整数,使得达到底边时的总和最小(或最大)。
当n=4时,例子如下:
总和最小为14,路径为2 -> 5 -> 1 -> 6
以下思路和算法实现参考自:数字三角形(动态规划)–算法学习
思路
先把最后一行写入新的n×n的二维数组中。再看原数组中第n-1行的第一个数1,比较它在三角形中加上左下角的数得到的结果小还是加上右下角的数得到的结果小,即比较1+8小还是1+6小。显然是1+6小,则将结果7写入新数组的同一个位置中。
类似的,可获得新数组第n-1行的所有元素。
遍历到原数组的第n-2行,就比较原数组中第n-2行的元素加上它在新数组中相应位置的左下角和右下角的数值哪个更小,并写入到相应的位置。如第n-2行的第一个元素5,比较5+7小还是5+10小。显然是5+7小,则将结果12写入。
最后可得到一个完整的新数组,而新数组的第一个元素值即为最小总和。而再从新数组的第一个元素起往下推,找左下角和右下角中小的那一个,即可在原数组的相应位置获得路径上的元素。如:
新数组中第一个数为14,路径的开始的数则为原数组的2;
14的左下角12小于右下角14,则路径中加入原数组的5;
12的左下角7小于右下角10,则路径中加入原数组的1;
7的左下角8大于右下角6,则路径中种加入原数组的6。
算法实现
#include<iostream>
using namespace std;
#define MAX 101
int N[MAX][MAX]; //存放等边三角形,上述思路中的原数组
int minSum[MAX][MAX]; //存放路径和,上述思路中的新数组
int n; //底边的数字个数
int main()
{
cout<<"输入三角形底边数字个数:";
cin>>n;
//初始化,我的二维数组是从[1][1]开始的
cout<<"输入数字构建等边三角形:";
for(int i=1;i<=n;i++)
{
for(int j=1;j<=i;j++)
{
cin>>N[i][j];
}
}
//将原数组的第n行写入新数组
for(int j=1;j<=n;j++)
{
minSum[n][j]=N[n][j];
}
//从下往上遍历,构建新数组
for(int i=n-1;i>=1;i--)
{
for(int j=1;j<=i;j++)
{
//min()函数不知道为啥用不了,暂时没解决,所以这里就用三元运算符了
int temp=minSum[i+1][j]<=minSum[i+1][j+1? minSum[i+1][j] : minSum[i+1][j+1];
minSum[i][j]=+N[i][j]+temp;
}
}
//新数组的第一个元素即为最小总和
cout<<"总和最小为:"<<minSum[1][1]<<endl;
//从上往下遍历,找到新数组与原数组中对应的元素,并输出。k为上一行的路径元素所在的列
cout<<"路径:";
cout<<N[1][1]<<" ";
int k=1;
for(int i=2;i<=n;i++)
{
if(minSum[i][k]<=minSum[i][k+1])
{
cout<<N[i][k]<<" ";
}
else
{
cout<<N[i][k+1]<<" ";
k=k+1;
}
}
return 0;
}
p.s.代码还有很多不足,朋友们有需要就自行修改,如果有问题也麻烦帮我指出来!