python 动态规划 数塔_动态规划—数塔问题

这篇博客介绍了一个利用Python解决数塔问题的方法,通过动态规划求解最大路径和。首先将数塔转化为二维数组,然后自底向上计算每个节点的最优路径,最后根据dp数组回溯并输出最优路径的选择。
摘要由CSDN通过智能技术生成

问题描述:

2a7f5cac0d58

image

如上图(图片来自网络)是一个数塔,从顶部出发在每一个节点都只能走到相邻的节点,也就是只能向左或者向右走,一直走到底层,要求找出一条路径,使得路径上的数字之和最大。

首先需要将具体问题抽象化,即将上面的数塔图先整理成一个二维数组:

int data[N][N] = {

{9,0,0,0,0},

{12,15,0,0,0},

{10,6,8,0,0},

{2,18,9,5,0},

{19,7,10,4,16}

};

然后根据分析这个数塔,再根据这个二维数组进行计算。

解决方案是自底至顶分析,自上而下计算。因此我们从第四层的四个数据开始分析:

如果最优路径经过2,那么一定经过19

如果最优路径经过18,那么一定经过10

如果最优路径经过9,那么一定经过10

如果最优路径经过5,那么一定经过16

因此,我们总结出规律:如果最有路径经过当前点

math?formula=(i%2Cj),那么从当前点到路径尾节点的数字之和

math?formula=dp%5Bi%5D%5Bj%5D将是当前点的值加上左右孩子其中较大的值,即:

math?formula=dp%5Bi%5D%5Bj%5D%20%3D%20max(dp%5Bi%2B1%5D%5Bj%5D%2C%20dp%5Bi%2B1%5D%5Bj%2B1%5D)%20%2B%20data%5Bi%5D%5Bj%5D%20%5Cqquad%E5%85%AC%E5%BC%8F1

公式1中我们多了个额外的数组int[][] dp,这个数组用来存储最终的结果。有了公式1,代码就很好写了:

public class CB {

public static void main(String[] args) {

int data[][] = {

{9, 0, 0, 0, 0},

{12, 15, 0, 0, 0},

{10, 6, 8, 0, 0},

{2, 18, 9, 5, 0},

{19, 7, 10, 4, 16}

};

int[][] dp = numberTower(data);

//打印出结果

for (int i = 0; i < dp.length; i++) {

System.out.println(Arrays.toString(dp[i]));

}

int i = 0, pre = 0;

System.out.println("选中->" + data[i][pre]);

for (i = 1; i < dp.length - 1; i++) {

int node_value = dp[i - 1][pre] - data[i - 1][pre];//默认选中的是左孩子

if (node_value == dp[i][pre + 1]) {//如果发现选中的是右孩子,那么pre加1

pre = pre + 1;

}

System.out.println("选中->" + data[i][pre]);

}

}

public static int[][] numberTower(int[][] data) {

int N = data.length;

int width = data[N - 1].length;

int[][] dp = new int[N + 1][width];//比原来的数塔多一层傀儡层

// dp初始化

for (int i = 0; i < width; ++i) {//需要给倒数第二层初始化赋值

dp[N - 1][i] = data[N - 1][i];

}

for (int i = N - 1; i >= 0; i--)

for (int j = 0; j < data[i].length - 1; j++)

dp[i][j] = (dp[i + 1][j] > dp[i + 1][j + 1] ? dp[i + 1][j] : dp[i + 1][j + 1]) + data[i][j];

return dp;

}

}

打印结果如下:

[59, 49, 29, 21, 0]

[50, 49, 29, 21, 0]

[38, 34, 29, 21, 0]

[21, 28, 19, 21, 0]

[19, 7, 10, 4, 16]

[0, 0, 0, 0, 0]

选中->9

选中->12

选中->10

选中->18

选中->10

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值