写的有点急可能有点乱,大家先将就下吧
题目:
描述:给定一个由n行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。
编程:对于给定的由n 行数字组成的数字三角形,编程计算从三角形的顶至底的路径经过的数字和的最大值。
输入:从文件(input.txt)中读入数据的第1 行是数字三角形的行数n,1<=n<=100。接下来n行是数字三角形各行中的数字。所有数字在0..99之间。
输出:程序运行结束时,将计算结果输出到文件(output.txt)。第1 行的数是计算出的最大值。
样例输入(input.txt):
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
样例输出(output.txt):
30
分析:(不用动态规划的前提下)
(1)单纯贪心算法是无法实现的,因为贪心算法只是局部最优,无法全局最优,所以不能用贪心算法的思路。
(2)我们只要把每一行的最大值算出来,再有选择的将此次的结果带入下一次运算,应该就可以实现。
思路:
我是这样想的,以上面用数字罗列的三角形为例,每一个数字的父节点只可能是他左上方的或正上方的,所以只要从第一行开始累积,每次都挑选出当前计算结果最大的,累加下来,备下一次用,直到最后,这样应该就OK了,所以关键问题就是在二维数组中找到它逻辑上来说的左上发和正上方的数,也就是找到他们的坐标。左上是[row-1,line-1],正上[row-1,line],一直累加到最后一行,再从最后一行中找出最大的数字,就是要的的结果了。
实现:
(这里没有动态去申请二位数字,直接一次性申请了100x100的数组,比较省劲,也没浪费太多内存)
#include
#include
int arr[100][100];
/****************************************************************
*函 数:int readfile(int * rowCount) *
*参 数:存储有多少行的变量指针 *
*功 能:从文件中读取信息并存储信息 *
*返 回:文件读取成功返回1否则返回0 *
*****************************************************************/
int readfile(int * rowCount)
{
FILE * file;
int loop = 0; //列循环变量
int circle = 0; //行循环变量
//以只读方式打开文件并判断打开是否成功
if(!(file = fopen("input.txt", "r")))
{
return 0;
}
fscanf(file, "%d", rowCount); //从文件中读数字(读出第一个数字(行数))
//循环读取文件中的数字(行计数)
for(loop = 0; loop < *rowCount; loop++)
{
//循环读取文件中的数字(列计数)
for(circle = 0; circle <= loop; circle++)
{
fscanf(file, " %d", &arr[loop][circle]); //继续循环读文件中的数字,存储进数组
}
}
fclose(file);
return 1;
}
/*****************************************
*函 数:int writefile(int maxNum) *
*参 数:待向文件中写入的最大数字 *
*功 能:向"output.txt"中写入数字 *
*返 回:文件写入成功返回1否则返回0 *
******************************************/
int writefile(int maxNum)
{
FILE * file;
//以只读方式打开文件并判断打开是否成功
if(!(file = fopen("output.txt", "w")))
{
return 0;
}
fprintf(file, "%d", maxNum); //向文件中输入数字
fclose(file);
return 1;
}
/****************************************************************
*函 数:int getMax(int loop, int circle) *
*参 数:(父节点)所在行,所在列 *
*功 能:判断指定行的指定列的前一个和当前数字中最大的并返回 *
*返 回:返回指定行的指定列的前一个和当前数字中最大的 *
*****************************************************************/
int getMax(int loop, int circle)
{
int num1, num2; //数字存储变量
//判断列数是否下越界
if(circle - 1 < 0)
{
return arr[loop][circle]; //存在越界,返回另一个数
}
//列未越界
else
{
num1 = arr[loop][circle - 1]; //存储此数
}
//判断列数是否上越界
if(circle > loop)
{
return num1; //存在越界,返回另一个书
}
//列未越界
else
{
num2 = arr[loop][circle]; //存储此数
}
return num1 > num2 ? num1 : num2; //两数都未越界,返回最大的
}
/**********************************************************
*函 数:int getTrianglesMax(int rowCount) *
*参 数:三角形行数 *
*功 能:遍历每一层并返回从顶到底路径和的最大值 *
*返 回:所有路径中最优路径上数字和的最大值 *
**********************************************************/
int getTrianglesMax(int rowCount)
{
int loop = 1; //行循环变量
int circle = 0; //列循环变量
int maxNum = 0; //存储最大数字
//数组行循环
for(; loop < rowCount; loop++)
{
//数组列循环
for(circle = 0; circle <= loop; circle++)
{
arr[loop][circle] += getMax(loop - 1, circle); //循环此列累加上此列对应上一行的的路径的最大值
}
}
//循环查找最后一行中的最大值
for(--loop, circle = 0; circle < rowCount; circle++)
{
//判断当前的循环的值是否比最大值大
if(maxNum < arr[loop][circle])
{
maxNum = arr[loop][circle]; //如果比最大值大,存储当前最大值
}
}
return maxNum; //返回最后获得的最大值
}
/*********************
*函 数:int main() *
*参 数:无 *
*功 能:主函数 *
*返 回:0 *
*********************/
int main()
{
int rowCount = 0; //存储行数
int maxNum = 0; //存储所求最大路径数值
//文件读取并判断是否成功
if(!readfile(&rowCount))
{
puts("read file error.");
exit(0);
}
//读取文件成功
maxNum = getTrianglesMax(rowCount); //遍历数组并获取最大路径的和
//将结果写入文件并判断文件是否写入成功
if(!writefile(maxNum))
{
puts("write file error.");
}
return 0;
}
总结:
其实很多问题可以不用动态规划解决,可能复杂点,但是思路上比想公式要简单得多。