C语言实现之三角形问题(非动态规划方法)

本文介绍了一种非动态规划方法解决数字三角形的最大路径和问题。通过从三角形的第一行开始,每次选择当前计算结果最大的数字进行累加,直到最后一行,找出最大的数字作为最终结果。虽然这种方法比动态规划复杂,但思路更直观。示例输入和输出分别给出了问题的定义和预期答案30。

写的有点急可能有点乱,大家先将就下吧吐舌头

题目:

        描述:给定一个由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 <stdio.h>
#include <stdlib.h>

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;
}


总结:

      其实很多问题可以不用动态规划解决,可能复杂点,但是思路上比想公式要简单得多。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值