精华内容
下载资源
问答
  • 实现3-4数字三角形问题.cpp
  • 10.1 什么是动态规划 前面学过了用递归的方法解决问题但是单纯的递归在解决某些问题的时候效率 会很低例如下面这道题目 例题数字三角形? 问题描述? 7? 3 8? 8 1 0? 2 7 4 4? 4 5 2 6 5? 上图给出了一个数字三角形从...
  • 数字三角形 c++

    2016-06-28 09:16:12
    数字三角形 c++
  • 信息奥赛课课通P174-1,蛇形数字三角形的C++程序代码。
  • 数字三角形

    2015-10-27 20:20:38
    数据结构 C++ 动态规划
  • 数字三角形.-动态规划,思路新颖易懂
  • 数字三角形最大路径

    2017-02-24 11:01:55
    用滚动数组实现最大路径问题
  • 主要介绍了C++数字三角形问题与dp算法的相关知识,非常不错,具有一定的参考借鉴价值 ,需要的朋友可以参考下
  • 数字三角形问题

    2012-02-21 16:18:21
    纯C++编写,并且提供input()输入,output()输出,保证运行成功!
  • 数字三角形问题.cpp

    2013-10-12 22:48:54
    有一个数字组成三角形,从上向下有一个路径,在这个路径中所有的数字相加求得最大的数.
  • C++/python描述 898. 数字三角形 (四种实现方法)

    千次阅读 多人点赞 2021-01-12 22:15:46
    数字三角形 (四种实现方法)   大家好,我叫亓官劼(qí guān jié ),在CSDN中记录学习的点滴历程,时光荏苒,未来可期,加油~博主目前仅在CSDN中写博客,唯一博客更新的地址为:亓官劼的博客 ,同时正在...

    C++/python描述 898. 数字三角形 (四种实现方法)

      大家好,我叫亓官劼(qí guān jié ),在CSDN中记录学习的点滴历程,时光荏苒,未来可期,加油~博主目前仅在CSDN中写博客,唯一博客更新的地址为:亓官劼的博客 ,同时正在尝试在B站中做一些内容分享,B站主页为: 亓官劼的B站主页

    本文原创为亓官劼,请大家支持原创,部分平台一直在恶意盗取博主的文章!!!
    若需联系博主,可以联系本人微信:qiguanjie2015


    题目

    给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。

            7
          3   8
        8   1   0
      2   7   4   4
    4   5   2   6   5
    

    输入格式

    第一行包含整数n,表示数字三角形的层数。

    接下来n行,每行包含若干整数,其中第 i 行表示数字三角形第 i 层包含的整数。

    输出格式

    输出一个整数,表示最大的路径数字和。

    数据范围

    1≤n≤500,
    −10000≤三角形中的整数≤10000

    输入样例:

    5
    7
    3 8
    8 1 0 
    2 7 4 4
    4 5 2 6 5
    

    输出样例:

    30
    

    给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。

            7
          3   8
        8   1   0
      2   7   4   4
    4   5   2   6   5
    

    输入格式

    第一行包含整数n,表示数字三角形的层数。

    接下来n行,每行包含若干整数,其中第 i 行表示数字三角形第 i 层包含的整数。

    输出格式

    输出一个整数,表示最大的路径数字和。

    数据范围

    1≤n≤500,
    −10000≤三角形中的整数≤10000

    输入样例:

    5
    7
    3 8
    8 1 0 
    2 7 4 4
    4 5 2 6 5
    

    输出样例:

    30
    

    题解思路

    这题可以使用动态规划的思想,第一行是起点,不需要动,从第二行开始,路径和最大值a[i][j]分为三种情况:

    • 第i行第1个数只能由第i-1行第1个数向左下走到
    • 第i行第i个数只能由第i-1行第i-1个数向右下走到
    • 第i行第2n-1个数,可以由第i-1行第2n-2个数走到,每次取其中最大值,状态转移方程为:a[i][j] += max(a[i-1][j-1],a[i-1][j])

    C++实现为:

    #include<iostream>
    using namespace std;
    int main(){
        int n;
        cin>>n;
        int a[505][505];
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= i; j++)
                scanf("%d",&a[i][j]);
        for(int i = 2; i <= n; i++){
            // 第i行第1个数只能由第i-1行第1个数向左下走到
            a[i][1] += a[i-1][1];
            // 第i行第2~n-1个数,可以由第i-1行第2~n-2个数走到
            // 从第二行开始向下走,最大值a[i][j] += max(a[i-1][j-1],a[i-1][j])
            for(int j = 2; j <= i-1; j++){
                a[i][j] += max(a[i-1][j-1],a[i-1][j]);
            }
            // 第i行第i个数只能由第i-1行第i-1个数向右下走到
            a[i][i] += a[i-1][i-1];
        }
        int ans = a[n][1];
        for(int i = 1; i <= n; i++){
            if(a[n][i] > ans)
                ans = a[n][i];
        }
               
        cout<<ans;
        return 0;
    }
    

    C++实现二:倒推实现

    #include<iostream>
    using namespace std;
    int main(){
        int n;
        cin>>n;
        // 开辟空间,赋值为0
        int a[505][505] = {0};
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= i; j++)
                scanf("%d",&a[i][j]);
        // 倒序dp,这样写放简单,不需要考虑边界问题
        // 从第n行向第1行倒推
        // 状态转移方程:a[i][j] += max(a[i+1][j],a[i+1][j+1])
        for(int i = n-1; i >= 1; i--){
            for(int j = 1; j <= i; j++){
                a[i][j] += max(a[i+1][j],a[i+1][j+1]);
            }
        }
        // 倒推到第一行,则a[1][1]即最大值
        cout<<a[1][1];
        return 0;
    }
    

    Python实现一:

    
    n = int(input())
    # store存储输入数据
    store = []
    # 输入
    for i in range(0,n):
        # 每次读入一行,int类型
        temp = list(map(int, input().split()))
        store.append(temp)
    # 注意这里是从0开始存储的,与C++实现时不同
    for i in range(1,n):
        # 第i行第0个数只能由第i-1行第0个数向左下走到
        store[i][0] += store[i-1][0]
        # 第i行第1~i-1个数,可以由第i-1行第1~i-1个数走到
        # 从第二行开始向下走,最大值store[i][j] += max(store[i-1][j-1],store[i-1][j])
        for j in range(1,i):
            store[i][j] += max(store[i-1][j-1],store[i-1][j])
        # 第i行第i+1个数只能由第i-1行第i个数向右下走到
        store[i][i] += store[i-1][i-1]
    # 记录最大值即返回值
    ans = store[n-1][0]
    for item in store[n-1]:
        if item > ans:
            ans = item
    print(ans)
    

    Python实现二:倒推实现

    # 自下往上做更方便
    
    N = int(input())
    # 多开一行,方便实现在1-N上存储,看起来更方便
    dp = [[0]*(N+1) for _ in range(N+2)]
    s = [[0]]
    for i in range(N):
        a = list(map(int, input().split()))
        s.append(a)
    for i in range(N, 0, -1):
        for j in range(i):
            dp[i][j] = max(dp[i+1][j], dp[i+1][j+1])+s[i][j]
    print(dp[1][0])
    
    
    展开全文
  • 【蓝桥杯】 算法训练 数字三角形

    千次阅读 2020-07-18 16:49:21
    历届试题 数字三角形 问题描述 在下面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或 右下走。只需要求出这个最大和即可,不必给出具体路径。 三角形的...

    历届试题 数字三角形

    问题描述
    在下面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或 右下走。只需要求出这个最大和即可,不必给出具体路径。 三角形的行数大于1小于等于100,数字为 0–99。
    数字三角形

    输入格式:
    第一行为一个整数n,表示接下来将要输入的三角形行数
    接下来是n行,每行输入当前行数的个数个数

    输出格式:输出一个数字,表示最大和

    样例输入:如上图

    样例输出:30
    数据说明:最大路径为(7-3-8-7-5)从上至下



    —— 初入江湖之动态规划 ——



    分析:
    这是一道经典的动态规划问题,我们还是从最浅显的算法出发,由浅到深慢慢研究
    首先最容易想到的,就是暴力搜索算法。我们先用一个二维数组map来存放上面的数字三角形,于是有:
    map[1][1]=7
    map[2][1]=3 map[2][2]=8
    map[3][1]=8 map[3][2]=1 map[3][3]=0
    ……
    然后我们假设,这里有一个名为dfs(x,y)的函数,该函数能从上述三角形中位置为(x,y)处出发,往其下自动寻找最大路径和,并返回这个和。那么对于题目输入的任何数字三角形,我们只需要输出dfs(1,1)即可
    接下来,我们的重点就落在了如何设计这个dfs函数上,这样的转换和汉诺塔问题挺像的,我们慢慢分析
    我们看图可以知道,在map[1][1]下面,只有两条路:要么选择map[2][1],要么选择map[2][2]
    也就是说,最大路径应该在这两者之间产生,那么我们为了选择最大路径和,当然是选较大的,即:
    return max( dfs(2,1),dfs(2,2) ) + map[1][1]
    同样地,在dfs(2,1)和dfs(2,2)中也一样,其分别也是选择在其下方中较大的,于是我们可以得出递归式:

    int dfs(int i,int j)
    {	
    	return max( dfs(i+1,j),dfs(i+1,j+1) ) + map[i][j];  
    }
    

    上述递归式中给出了程序在自顶向下进行寻找最大路径和的过程,但是却没有给出中止条件
    细想,当i走到了最后一行时(即i==n)时,我们的dfs函数就不能再往下dfs下去了,那么此时我们就直接返回值就行了,于是可以得到采用递归方法进行求解的完整代码为:

    #include<iostream>
    using namespace std;
    
    const int N=105;
    int n,map[N][N];
    int dfs(int i,int j)
    {
    	if(i==n) return map[i][j];
    	else return max(dfs(i+1,j),dfs(i+1,j+1))+map[i][j];
    }
    
    int main()
    {
    	cin>>n;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=i;j++)
    			cin>>map[i][j];
    	cout<<dfs(1,1)<<endl;
    	return 0;
    }
    

    提交这个代码上去,只得了57分(过了4/7的数据)
    得到这样的结果是很正常的。要知道,递归是需要使用大量堆栈上的空间,极易造成栈溢出。而通常在递归树超过了50层的时候,就会消耗大量的时间和空间。并且根据前面“动态规划之斐波那契数列”对递归算法的分析,我们知道递归做了大量的重复工作。因此,为了能通过所有的测试数据,我们就需要用一个数组来保存前面已经算出的结果,从而使得递归变为递推

    根据dfs算法的思路,程序总会dfs到最后一行,然后开始选择最大值,那么我们的表格也应该是从最后一行开始填写,如下图所示,我们首先把最下面一行填入表格中:
    填表
    然后开始倒数第二行的填写。先分析数字2,2可以和最后一行4相加,也可以和最后一行的5相加,但是很显然和5相加要更大一点,结果为7,我们此时就可以将7保存起来;然后分析数字7,7可以和最后一行的5相加,也可以和最后一行的2相加,很显然和5相加更大,结果为12,因此我们将12保存起来。以此类推……最终可以得到下面这张图:
    填表
    然后按同样的方法填写倒数第三行和倒数第四行,直至第一行,我们可以依次得到如下结果:
    填表
    如果设maxSum(i,j)表示坐标为(i,j)的位置通向最后一行所寻找到的最大路径和
    那么根据上面的推导过程,我们可以得到这里面的递推公式为:
    maxSum[ i ][ j ] = max( maxSum[ i+1 ][ j ],maxSum[ i+1 ][ j+1 ] ) + map[ i ][ j ];
    根据这样的思路写出的完整代码如下:

    #include<iostream>
    using namespace std;
    const int N=105;
    int n,map[N][N],maxSum[N][N];
    void dp()
    {
    	for(int i=1;i<=n;i++) maxSum[n][i]=map[n][i];
    	for(int i=n-1;i>=1;i--)
    		for(int j=1;j<=i;j++)
    			maxSum[i][j] = max(maxSum[i+1][j],maxSum[i+1][j+1]) + map[i][j];
    }
    int main()
    {
    	cin>>n;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=i;j++)
    			cin>>map[i][j];
    	dp();
    	cout<<maxSum[1][1]<<endl;
    	return 0;
    }
    

    实际上,我们没有必要用一个maxSum[N][N]数组来进行递推,我们就在map[N][N]数组上就行,即:

    #include<iostream>
    using namespace std;
    
    const int N=105;
    int n,map[N][N];
    void dp()
    {
    	for(int i=n-1;i>=1;i--)
    		for(int j=1;j<=i;j++)
    			map[i][j] = max(map[i+1][j],map[i+1][j+1]) + map[i][j];
    }
    
    int main()
    {
    	cin>>n;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=i;j++)
    			cin>>map[i][j];
    	dp();
    	cout<<map[1][1]<<endl;
    	return 0;
    }
    


    —— 翻山越岭之内存优化 ——



    更进一步,我们甚至连二维矩阵都不需要,直接用两个一维数组就行,一个一维数组num[N]用于存放当前输入的某一行数字;另一个一维数组lastNum[N]用于存放对某行进行操作后的情况。显然,这种处理办法是基于对输入的数字三角形进行行处理而得到的,但是题目给出的数字三角形的输入是从上往下进行的,而上面介绍的所有求解办法都是从下往上进行的。因此,在介绍用两个一维数组进行处理的办法前,需要先介绍下从上往下解答的算法。老规矩,从填表开始:
    填表
    第一次,由于第一行只有一个数字,因此得到的表格如下:
    填表
    第二次,此时往下走,由于出发点只有一个数字7,且终点也只有两个数字(分别为3和8),因此从第一行往二行走的办法只有两条,无需选择,于是得到的表格如下:
    填表
    第三次,此时出发点就有两个了,我们把目光主要放在第三行,比如现在针对第三行第一列的数字8,其只能由其上方的数字3走来,于是得到第三行第一列的路径和为7+3+8=18;然后看第三行第二列的数字1,其可以由其上方的数字3和数字8走来,但是显然,从数字8走来会使得路径和更大,因此第三行第二列的路径和为7+8+1=16;最后是第三行第三列的数字0,其也只能从其上方的数字8走来,于是得到第三行第三列的路径和为7+8+0=15。最终得到的表格如下:
    填表
    按照这样的思路继续填表,得到的表格内容依次如下:
    填表
    最终,表格的最下边那一行装填了从整个数字三角形顶端到底端各个出口的最大路径和。如果我们要求解这其中的最大值就还需要写一个取数组maxSum[n][n]={24,30,27,26,24}最大值的函数
    实际上,在上面的填表过程中,动态转移方程变成了(设原始数据存放在map[N][N]中,所填的表格为maxSum[N][N]):
    maxSum[ i ][ j ] = max( maxSum[ i-1 ][ j-1 ],maxSum[ i-1 ][ j ] ) + map[ i ][ j ]
    同样地,这里我们也可以不用maxSum[N][N]数组,而是直接在map[N][N]中进行动态转移变换:
    map[ i ][ j ] = max( map[ i-1 ][ j-1 ],map[ i-1 ][ j ] ) + map[ i ][ j ]

    采用这种方法求解本题题的完整代码如下:

    #include<iostream>
    using namespace std;
    
    const int N=105;
    int n,map[N][N];
    void dp()
    {
    	for(int i=2;i<=n;i++)
    		for(int j=1;j<=i;j++)
    			map[i][j] = max(map[i-1][j-1],map[i-1][j]) + map[i][j];
    }
    int maxValue()
    {
    	int max=map[n][1];
    	for(int i=2;i<=n;i++)
    		if(map[n][i]>max) max=map[n][i];
    	return max;
    }
    
    int main()
    {
    	cin>>n;
    	for(int i=1;i<=n;i++)
    		for(int j=1;j<=i;j++)
    			cin>>map[i][j];
    	dp();
    	cout<<maxValue()<<endl;
    	return 0;
    }
    


    —— 登峰造极之递推求解 ——



    上面的内容是个小插曲,主要是为了让大家熟悉从上往下解题的方法。别忘了我们的初衷是要优化程序的空间为两个一维数组,下面开始介绍具体的做法。同样地,我们依然填表开始,如下:
    填表
    首先是将第一行的数据输入num[N]数组,如下:
    填表
    然后再更新num[N]数组中的某个元素num[i]为max( lastNum[ i ],lastNum[ i-1 ] )+num[ i ],如下:
    填表
    最后将num[N]数组中的内容复制到lastNum[N]数组中,如下:
    填表


    接下来到了第2行,同样地先将整行数据输入num[N]数组中,即num[N]={3,8},如下:
    填表
    然后将num[N]数组中的某个元素num[i]更新为max( lastNum[i],lastNum[i-1] )+num[i],如下:
    填表
    最后将num[N]数组中的内容复制到lastNum[N]数组中,如下:
    填表
    然后按照这样的方式不断更新lastNum[N]数组,如下:
    填表

    填表

    填表
    最终,在lastNum[N]数组中存储的就是该数字三角形自顶向下往金字塔底部每个数字出去的最大路径和,为了取得这之间的最大值我们就还需要写一个对某数组求解最大值的函数
    此外还需要提的一点是,上述算法我们需要将num[N]数组中的内容更新到lastNum[N]数组中。在上面的演示中我采用的是复制过去的方式。我们知道,复制某个数组到另一个数组是一个线性的时间复杂度,那么在具有n行的数字金字塔中,上述算法在复制数组上的时间复杂度就变成了O(n2/2)。如果为了降低空间复杂度而使得程序的时间复杂度增加,这样是得不偿失的。但是我们可以采用指针来完成这项工作!
    即通过用指针来改变指向的数组即可,这样就避免了数组的复制,从而使得时间复杂度不变
    下面直接给出使用此方法求解本题的完整代码:

    #include<iostream>
    using namespace std;
    
    const int N=105;
    int n,*num,*lastNum,ary1[N],ary2[N];
    void dp()
    {
    	num=ary1,lastNum=ary2;
    	for(int i=1;i<=n;i++){
    		for(int j=1;j<=i;j++){
    			cin>>num[j];
    			num[j]=max(lastNum[j],lastNum[j-1])+num[j];
    		}
    		swap(num,lastNum);
    	}
    
    }
    int maxValue()
    {
    	int max=lastNum[1];
    	for(int i=2;i<=n;i++)
    		if(lastNum[i]>max) max=lastNum[i];
    	return max;
    }
    
    int main()
    {
    	cin>>n;dp();
    	cout<<maxValue()<<endl;
    	return 0;
    }
    



    展开全文
  • 数字三角形(C语言编写) 算法
  • Problem B:数字三角形问题 Description 给定一个由n行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形 的顶至底的一条路径,使该路径经过的数字总和最大。 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 ...
  • 问题描述:给字一个由n行数字组成的数字三角形,如图3-7所示。试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。 ★算法设计:对于给定的由n行数字组成的数字三角形,计算从三角形的...
  • C++ 数字三角形(动态规划)

    千次阅读 2019-01-25 10:29:08
    // 调用函数:求得数字三角形中从第一行到各个位置的权值之和最大的数 MaxSum(n); t = 0; // 比较最后一行的权值之和,找到最大的一个输出 for(i = 0; i ; i++) { if(t [n-1][i]) t = opt...

    一、题目

        

       有三种方法实现: 这里就求权值之和最大的,最小的类似就不分析了。

       1.自底向上  缺点:算法复杂,重复计算

       2.自顶向下  缺点:重复计算,浪费时间

       3.动态规划 思路和自底向上、自顶向下一样,只不过开多一个数组opt存储计算过的到达a[i][j]的权值之和最大的数

     

    二、思路:

         方法1:自底向上

         1.从最后一行出发,例如,最后一行的2:

            如何得到走到2的权值之和最大数?(用递归

                   那就要先得到走到左上角的数(7)的权值之和最大的数,正上方的数(4)的权值之和最大的数。

            再比较两者哪个大,大的一个加上最后一行的数2,就是走到2的权值之和最大的数;

            同样,如何得到走到7的权值之和最大的数?或者是走到4的权值之和的最大数

                  就要先得到7的左上角的数(8)的权值之和的最大数,和正上方的数(1)的权值之和的最大数,再

            比较这两个权值之和哪个大,大的加上7;

            ……

            一直递推到第一行的数a[0][0],返回a[0][0]的值,然后回归,求得到达2的权值之和的最大数;

         2.比较走到最后一行(4,5,2,6,5)的各个权值之和,取得权值之和最大的数,然后输出

        实现程序:

    //  数字三角形
    //  7
    //  3 8
    //  8 1 0
    //  2 7 4 4
    //  4 5 2 6 5
    //  找出从第一层到最后一层的一条路,使得经过的权值之和最小或者最大,
    //  每一步只能向下或向右下方走。
    //  第一种方法:自底向上的思路
    //       缺点:算法有点复杂
    //  思路:从下面一个数开始往上计算,取sum(i-1, j-1)和sum(i-1, j)的最大值(即前面的权值之和最大值),加上当前值
    
    #include <iostream>
    
    const int max = 100;
    int a[max][max];
    int sum(int i, int j);
    
    int main(int argc, const char * argv[]) {
        int m = 0;
        int i, j, t, n;
        
        std::cin >> n; // 行数
        for(i = 0; i < n; i++) // 输入数字三角形
            for(j = 0; j <= i; j++)
                std::cin >> a[i][j];
        for(j = n-1; j >= 0; j--) {
            t = sum(n-1, j); // 计算走到最后一行每个数的权值之和
            if(m < t)
                m = t;
        }
        std::cout << m << std::endl;
        return 0;
    }
    
    // 递归:求走到第i行和第j列的权值之和最大的数
    int sum(int i, int j) {
        int x, y;
        
        if(i < j)
            return 0;
        if(i == 0)
            return a[0][0];
        else {
            x = sum(i-1, j-1); // 求到达左上角的数的权值之和最大数
            y = sum(i-1, j); // 求到达正上方的数的权值之和最大数
            if(x > y)
                return x+a[i][j];
            else
                return y+a[i][j];
        }
    }

    测试结果:

    方法2:自顶向下 和自底向上的思路刚好相反

        1.从a[0][0]出发:

           递推:得到从最后一行到正下方a[1][0]的权值之和最大的数,和从最后一行到右下方a[1][1]的权值之和最大的数

           回归:究竟是最后一行到a[1][0]的权值之和大,还是最后一行到达a[1][1]的权值之和大

                     取权值之和较大的,然后加上a[0][0],就是所求的权值之和最大的数

           那如何求得最后一行到a[1][0]的权值之和最大的数?或者是到a[1][1]的

           同样,求最后一行到正下方的数a[2][0]的权值之和,然后求最后一行到右下方的数a[2][1]的权值之和;

           取较大的权值之和,加上a[1][0]

           …

           一直递推,直到最后一行,然后返回最后一行的数

          接着回归求得从最后一行到a[0][0]的权值之和最大的数

        

        2.实现程序:

    //  数字三角形
    //  7
    //  3 8
    //  8 1 0
    //  2 7 4 4
    //  4 5 2 6 5
    //  找出从第一层到最后一层的一条路,使得经过的权值之和最小或者最大,
    //  每一步只能向下或向右下方走。
    //  第二种方法:自顶向下的思路
    //  缺点:重复计算,浪费时间
    
    #include <iostream>
    
    const int max = 100;
    int a[max][max];
    int sum(int i, int j, int n); // 取得到达最后一行的权值之和最大的数
    
    int main(int argc, const char * argv[]) {
        int i, j, n;
        
        std::cin >> n; // 输入行数
        // 输入数字三角形
        for(i = 0; i < n; i++)
            for(j = 0; j <= i; j++)
                std::cin >> a[i][j];
        std::cout << sum(0, 0, n) << std::endl; // 调用函数
        return 0;
    }
    
    // 取得到达最后一行的权值之和最大的数
    int sum(int i, int j, int n) {
        int x, y;
        
        if(i == n-1) // 到最后一行,返回最后一行的数
            return a[i][j];
        else {
            x = sum(i+1, j, n); // 求得最后一行到a[i+1][j]的权值之和最大的数
            y = sum(i+1, j+1, n); // 求得最后一行到a[i+1][j+1]的权值之和最大的数
            if(x>y) // 取权值之和较大的加上a[i][j]
                return x+a[i][j];
            else
                return y+a[i][j];
        }
    }

    方法3动态规划

    1.思路:和自底向上和自顶向下思路一样,只不过,用多一个数组opt存储计算过的到达a[i][j]的权值之和最大的数

    2.实现方法1:自顶向下(结合动态规划)

    //  数字三角形
    //  7
    //  3 8
    //  8 1 0
    //  2 7 4 4
    //  4 5 2 6 5
    //  找出从第一层到最后一层的一条路,使得经过的权值之和最小或者最大,
    //  每一步只能向下或向右下方走。
    //  第三种方法:记忆化搜索,递归,自顶向下
    
    #include <iostream>
    
    const int MAX = 100;
    int a[MAX][MAX];
    int opt[MAX][MAX];
    int sum(int i, int j, int n); // 计算
    
    int main(int argc, const char * argv[]) {
        int i, j, n;
        
        std::cin >> n;
        memset(opt, 0, sizeof(opt)); // 清零
        // 输入数字三角形
        for(i = 0; i < n; i++)
            for(j = 0; j <= i; j++)
                std::cin >> a[i][j];
        std::cout << sum(0, 0, n) << std::endl; // 调用函数,求得最大的权值之和
        return 0;
    }
    
    // 递归:求最后一行到a[i][j]的权值之和最大的数
    int sum(int i, int j, int n) {
        if(opt[i][j] != 0) // 之前已经求过,直接返回
            return opt[i][j];
        if(i == n-1) { // 到达最后一行
            opt[i][j] = a[i][j];
            return a[i][j];
        } else {
            opt[i+1][j] = sum(i+1, j, n); // 求得最后一行到a[i+1][j]的权值之和最大的数
            opt[i+1][j+1] = sum(i+1, j+1, n); // 求得最后一行到a[i+1][j+1]的权值之和最大的数
            if(opt[i+1][j] > opt[i+1][j+1]) // 取权值之和较大的加上a[i][j]
                return opt[i+1][j] + a[i][j]; // 最后一行到a[i][j]的权值之和最大的数
            else
                return opt[i+1][j+1] + a[i][j];
        }
    }

    方法2:自底向上(结合动态规划)

    #include <iostream>
    
    const int max = 100;
    int a[max][max];
    int opt[max][max];
    void MaxSum(int n); // 求得数字三角形中从第一行到各个位置的权值之和最大的数
    
    int main(int argc, const char * argv[]) {
        int i, j, n, t;
        
        std::cin >> n; // 输入行数
        memset(opt, 0, sizeof(opt)); // 清零
        // 输入数字三角形
        for(i = 0; i < n; i++)
            for(j = 0; j <= i; j++)
                std::cin >> a[i][j];
        // 调用函数:求得数字三角形中从第一行到各个位置的权值之和最大的数
        MaxSum(n);
        t = 0;
        // 比较最后一行的权值之和,找到最大的一个输出
        for(i = 0; i < n; i++) {
            if(t < opt[n-1][i])
                t = opt[n-1][i];
        }
        std::cout << t << std::endl;
        return 0;
    }
    
    // 求得数字三角形中从第一行到各个位置的权值之和最大的数
    void MaxSum(int n) {
        int i, j;
        
        opt[0][0] = a[0][0];
        for(i = 1; i < n; i++) {
            // 计算每行第一个数的权值之和
            opt[i][0] = opt[i-1][0] + a[i][0];
            // 计算除开头和结尾之外的其他位置权值之和
            for(j = 1; j < i - 1; j++) {
                if(a[i][j]+opt[i-1][j] >= a[i][j]+opt[i-1][j-1])
                    opt[i][j] = a[i][j]+opt[i-1][j];
                else
                    opt[i][j] = a[i][j]+opt[i-1][j-1];
            }
            // 计算每行最后一个数的权值之和
            opt[i][i] = a[i][j]+opt[i-1][i-1];
        }
    }

     

    展开全文
  • 数字三角形问题详解

    千次阅读 多人点赞 2019-11-10 00:29:02
    数字三角形问题详解 题目描述 给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。

    数字三角形问题详解


    在线提交地址请点击题目
    若有任何疑问,欢迎留言 (*^_^*)


    题目描述

    给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。

            7
          3   8
        8   1   0
      2   7   4   4
    4   5   2   6   5
    

    输入格式

    第一行包含整数 n,表示数字三角形的层数。
    接下来 n 行,每行包含若干整数,其中第 i 行表示数字三角形第 i 层包含的整数。

    输出格式

    输出一个整数,表示最大的路径数字和。

    输入样例

    3
    1
    2 3
    3 1 4
    

    输出样例

    8
    

    数据范围

    1 ≤ n ≤ 500,
    − 10000 −10000 10000 ≤ 三角形中的整数 ≤ 10000 10000 10000

    解题分析

    在这道题中,所需求解的原问题是:寻找一条从 ( 1 , 1 ) (1,1) (1,1) ( n , j )   1 ≤ j ≤ n (n,j)\ 1 \le j \le n (n,j) 1jn 的路径,使得路径上所经过数字的和最大。

    第一步拆分
    经过分析发现,原问题所求的是 所有到达最后一行 n n n 中每一个数的最大的路径当中,最大的那一条,即 m a x ( f [ n , j ] )   1 ≤ j ≤ n max(f[n, j])\ 1 \le j \le n max(f[n,j]) 1jn f [ n , j ] f[n,j] f[n,j] 为到达当前位置 ( n , j ) (n,j) (n,j) 的最大值。

    若加粗文字较难理解,请结合例子与表达式进行思考。

    举个例子,如下图所示:

    在这里插入图片描述

    ( 1 , 1 ) (1,1) (1,1) ( 3 , 1 ) (3,1) (3,1) 的最大值为 6 6 6 ,从 ( 1 , 1 ) (1,1) (1,1) ( 3 , 2 ) (3,2) (3,2) 的最大值为 5 5 5 ,从 ( 1 , 1 ) (1,1) (1,1) ( 3 , 3 ) (3,3) (3,3) 的最大值为 8 8 8 。根据题意,原问题的解为从 ( 1 , 1 ) (1,1) (1,1) ( 3 , 1 ) , ( 3 , 2 ) , ( 3 , 3 ) (3,1),(3,2),(3,3) (3,1),(3,2),(3,3) 中的最大路径的最大的值,故本题的解为 8 8 8

    第二步拆分
    如下图所示,从 i i i 行到 i + 1 i+1 i+1 行有两种方式, 一种是向左下走,另一种是向右下走。同理 ( i , j ) (i,j) (i,j) 可由 ( i − 1 , j ) (i-1,j) (i1,j) ( i − 1 , j − 1 ) (i-1,j-1) (i1,j1) 到达。

    因此,可将第一步所拆分的子问题( m a x ( f [ n , j ] ) max(f[n, j]) max(f[n,j]) )继续拆分成到达 ( i , j ) (i,j) (i,j) 的最大值 f [ i , j ] f[i,j] f[i,j]。因为所求的值为最大值,若使得 f [ i , j ] f[i,j] f[i,j] 最大,则需选则两种转移方案 f ( i − 1 , j ) f(i-1,j) f(i1,j) f ( i − 1 , j − 1 ) f(i-1,j-1) f(i1,j1) 中值较大的一种。能够这样转移的关键在于,这道题满足最优子结构性质,即原问题所有转移方案中最优的方案,仍为原问题的最优解。

    由此可以得出动态转移方程: f [ i , j ] = m a x ( f [ i − 1 , j ] , f [ i − 1 , j − 1 ] ) + a [ i , j ] f[i, j] = max(f[i - 1, j], f[i - 1, j - 1]) + a[i,j] f[i,j]=max(f[i1,j],f[i1,j1])+a[i,j],其中 a [ i , j ] a[i,j] a[i,j] ( i , j ) (i,j) (i,j) 位置上的数。

    参考代码

    希望各位读者能够在阅读代码前独立完成

    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int N = 510, INF = 1e9;
    
    int n, a[N][N], f[N][N];
    
    int main()
    {
        scanf("%d", &n);
        for (int i = 1; i <= n; i ++ )
            for (int j = 1; j <= i; j ++ )
                scanf("%d", &a[i][j]);
    
        for (int i = 0; i <= n; i ++ )
            for (int j = 0; j <= i + 1; j ++ )
                f[i][j] = -INF;
    
        f[1][1] = a[1][1];
        for (int i = 2; i <= n; i ++ )
            for (int j = 1; j <= i; j ++ )
                f[i][j] = max(f[i - 1][j - 1] + a[i][j], f[i - 1][j] + a[i][j]);
    
        int res = -INF;
        for (int i = 1; i <= n; i ++ ) 
        	res = max(res, f[n][i]);
    
        printf("%d\n", res);
        
        return 0;
    }
    

    本文从属于《动态规划入门指南》系列,更多动态规划问题的思维分析请点击链接查看。

    展开全文
  • 递归输出数字三角形

    2021-11-10 09:17:21
    试题 算法训练 递归输出数字三角形 问题描述 输出一个n行的与样例类似的数字三角形,必须使用递归来实现 输入格式  一个正整数数n,表示三角形的行数 输出格式  输出一个与样例类似的n行的数字三角形,同一行每两个...
  • 数字三角形(python)

    千次阅读 2020-12-17 16:27:01
    数字三角形的打印(python) 方法一: # 最常规打印法 # 利用空格进行右对其 n = 12 for i in range(1, n + 1): for j in range(n ,0, -1): if j > i: print(" " * len(str(j)), end=" ") else: print(j, ...
  • ACM 动态规划之数字三角形 有三种解决方式: 1、递归方法 2、递推方法 3、记忆化搜索

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 50,894
精华内容 20,357
关键字:

数字三角形