数塔问题

1、问题简述

       有形如图所示的一个数塔,从顶部出发,在每一结点可以选择向左走或是向右走,一直走到底层,要求找出一条路径,使路径上的数值和最大。 

                                                                           

2、问题分析

这个问题用贪婪算法有可能会找不到真正的最大和。以图为例就是如此。用贪婪的策略,则路径和分别为9+15+8+9+10=51 (自上而下),19+2+10+12+9=52(自下而上),都得不到最优解,真正的最大和是9+12+10+18+10=59。在知道数塔的全貌的前提下,可以用枚举法或下一章将学习的搜索算法来完成。

动态规划设计过程如下:

(1) 阶段划分:第一步对于第五层的数据,我们做如下五次决策:对经过第四层2的路径选择第五层的19,对经过第四层18的路径选择第五层的10, 对经过第四层9的路径也选择第五层的10,对经过第四层5的路径选择第五层的16。

以上的决策结果将五阶数塔问题变为4阶子问题,递推出第四层与第五层的和为:21(2+19),28(18+10),19(9+10),21(5+16)。用同样的方法还可以将4阶数塔问题,变为3阶数塔问题…… 最后得到的1阶数塔问题,就是整个问题的最优解。

(2)存储、求解: 原始信息存储:原始信息有层数和数塔中的数据,层数用一个整型 变量n存储,数塔中的数据用二维数组data,存储成如 下的下三角阵:

              9

             12    15

             10     6      8

              2    18      9    5

             19     7     10    4   16

动态规划过程存储:必需用二维数组a存储各阶段的决策结果。二维数组a的存储内容如下:d[n][j]=data[n][j] ,j=1,2,……,n; i=n-1,n-2,……1,j=1,2,……,i;时 d[i][j]=max(d[i+1][j],d[i+1][j+1])+data[i][j], 最后a[1][1]存储的就是问题的结果

最优解路径求解及存储:仅有数组data和数组a可以找到最优解的路径, 但需要自顶向下比较数组data和数组a是可以找到。如图4.5.2求解和输出过程如下:

 输出a[1][1]"9"

  b=d[1][1]-data[1][1]=59-9=50   b与d[2][1],d[2][2] 比较

  b与d[2][1]相等输出data[2][1]"12"

  b=d[2][1]-data[2][1]=50-12=38   b与d[3][1],d[3][2] 比较

  b与d[3][1]相等输出data[3][1]"10"

  b=a[3][1]-data[3][1]=38-10=28    b与d[4][1],d[4][2] 比较

  b与d[4][2]相等输出data[4][2]"18"

  b=d[4][2]-data[4][2]=28-18=10  b与d[5][2],d[5][3] 比较

  b与d[5][3]相等输出data[5][3]"10“

 

  数组data                       数组d

    9                                59

    12  15                        50  49

    10  6   8                     38  34  29

    2   18  9   5                21  28  19  21

    19  7   10  4  16         19  7   10  4   16

为了设计简洁的算法,我们最后用三维数组a[50][50][3]存储以上确定的三个数组的信息。 

            array[50][50][1]代替数组data,

            array[50][50][2]代替数组d,

            array[50][50][3]记录解路径。

3、Java实现代码

import java.util.Scanner;
public class 数塔 {
	public static void main(String[] args) {
		int array[][][] = new int[50][50][4];
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		sc.nextLine();
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= i; j++) {
				array[i][j][1] = sc.nextInt();
				array[i][j][2] = array[i][j][1];
				array[i][j][3] = 0;
			}
			sc.nextLine();
		}
		sc.close();
		for (int i = n - 1; i >= 1; i--) {
			for (int j = 1; j <= i; j++) {
				if(array[i+1][j][2] > array[i+1][j+1][2]) {
					array[i][j][2] = array[i][j][2] + array[i+1][j][2];
					array[i][j][3] = 0;
				}else {
					array[i][j][2] = array[i][j][2] + array[i+1][j+1][2];
					array[i][j][3] = 1;
				}
			}
		}
		System.out.println("maxNum = "+array[1][1][2]);
		int j = 1;
		int i = 1;
		for (i = 1; i < n; i++) {
			System.out.print(array[i][j][1]+"-->");
			j = j + array[i][j][3];
		}
		System.out.println(array[i][j][1]);
		
	}
}

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Python数塔问题一个经典的动态规划问题,主要是求解从顶部开始,通过相邻节点的选择,找到一条路径使得路径上的节点和最小。 通过引用的代码可以看出,这段代码使用了自底向上的动态规划方法来解决数塔问题。首先,初始化一个mini列表,将其设置为数塔的最后一行节点的值。然后,从倒数第二行开始,通过一个循环遍历每一行的节点。在每个节点上,选择该节点和其相邻节点的较小值,将其更新到mini列表中。最后,返回mini列表的第一个元素,即为最小路径和。 而引用的代码是使用递归的方法来解决数塔问题。在这段代码中,traverse函数接受两个参数i和j,表示当前节点的位置。如果当前节点是数塔的最后一行,即i大于等于总行数-1,那么返回0。否则,通过递归调用traverse函数,分别计算左下节点和右下节点的路径和,并返回较小值。最后,将当前节点的值加上较小路径和,即为最小路径和。 综上所述,以上两种方法都可以用来解决Python数塔问题,其中动态规划方法更为高效,递归方法则更为简洁。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [python解决数塔问题(递归,剪枝,DP)](https://blog.csdn.net/qq_45268474/article/details/108072826)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值