【题解 | 基础动态规划】:数字三角形

这篇具有很好参考价值的文章主要介绍了【题解 | 基础动态规划】:数字三角形。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

数字三角形

链接:[USACO1.5] [IOI1994]数字三角形 Number Triangles

题目描述

观察下面的数字金字塔。

写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

【题解 | 基础动态规划】:数字三角形,# 题解记录,动态规划,算法,java,C++

在上面的样例中,从 7 → 3 → 8 → 7 → 5 7 \to 3 \to 8 \to 7 \to 5 73875 的路径产生了最大权值。

输入格式

第一个行一个正整数 r r r ,表示行的数目。

后面每行为这个数字金字塔特定行包含的整数。

输出格式

单独的一行,包含那个可能得到的最大的和。

样例 #1

样例输入 #1

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

样例输出 #1

30

提示

【数据范围】
对于 100 % 100\% 100% 的数据, 1 ≤ r ≤ 1000 1\le r \le 1000 1r1000,所有输入在 [ 0 , 100 ] [0,100] [0,100] 范围内。

题目翻译来自NOCOW。

USACO Training Section 1.5

IOI1994 Day1T1


参考代码

这道题就是很裸的DP,也是很经典的入门题。我们先用记忆化搜索写一遍,再来写DP。

(1)记忆化搜索

我们首先读取金字塔的行数 r 和每行的数字,并存储在二维数组 triangle 中。然后,我们使用记忆化搜索的深度优先搜索函数 dfs 来计算从金字塔顶部到底部的最大路径和。

dfs 函数中,如果已经计算过当前位置到底部的最大路径和,我们直接返回结果;如果已经到达最后一行,我们返回当前值;否则,我们返回从当前位置到底部的最大路径和,并将结果存储在记忆化搜索数组 memo 中,以便后续使用。

最后,我们输出最大路径和。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {
    // 快读快写
    public static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    public static StreamTokenizer in = new StreamTokenizer(br);
    public static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
    
    public static int[][] triangle;
    public static Integer[][] memo;  // 用于记忆化搜索的数组

    public static void main(String[] args) throws IOException {
        // 读数据
        in.nextToken();
        int r = (int) in.nval;
        triangle = new int[r][];
        memo = new Integer[r][r];  // 初始化备忘录
        for (int i = 0; i < r; i++) {
            triangle[i] = new int[i+1];
            for (int j = 0; j <= i; j++) {
                in.nextToken();
                triangle[i][j] = (int) in.nval;
            }
        }

        // 记忆化搜索
        int maxSum = dfs(0, 0, r);

        out.println(maxSum);
        out.flush();
        br.close();
        out.close();
    }

    public static int dfs(int i, int j, int r) {
        // 如果已经计算过,直接返回结果
        if (memo[i][j] != null) {
            return memo[i][j];
        }
        // 如果已经到达最后一行,返回当前值
        if (i == r - 1) {
            return memo[i][j] = triangle[i][j];
        }
        // 否则,返回从当前位置到底部的最大路径和
        return memo[i][j] = triangle[i][j] + Math.max(dfs(i + 1, j, r), dfs(i + 1, j + 1, r));
    }
}

记忆化搜索是一种优化技术,主要用于优化递归算法,避免重复计算相同的子问题。它的主要思路是将已经计算过的子问题的结果存储起来,当再次遇到相同的子问题时,直接从存储的结果中获取,而不是重新计算。

(2)动态规划

下面我们来看DP的解法:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

public class Main {
	public static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	public static StreamTokenizer in = new StreamTokenizer(br);
	public static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

    public static void main(String[] args) throws IOException {
    	// 读数据
        in.nextToken();
        int r = (int) in.nval;
        int[][] triangle = new int[r][];
        for (int i = 0; i < r; i++) {
            triangle[i] = new int[i+1];
            for (int j = 0; j <= i; j++) {
                in.nextToken();
                triangle[i][j] = (int) in.nval;
            }
        }

        // 动态规划
        int[][] dp = new int[r][r];
        dp[0][0] = triangle[0][0];
        for (int i = 1; i < r; i++) {
            for (int j = 0; j <= i; j++) {
                if (j == 0) {
                    dp[i][j] = dp[i-1][j] + triangle[i][j];
                } else if (j == i) {
                    dp[i][j] = dp[i-1][j-1] + triangle[i][j];
                } else {
                    dp[i][j] = Math.max(dp[i-1][j-1], dp[i-1][j]) + triangle[i][j];
                }
            }
        }

		// 筛选答案(找到最后一行每个位置的路径和最大值)
        int maxSum = dp[r-1][0];
        for (int i = 1; i < r; i++) {
            maxSum = Math.max(maxSum, dp[r-1][i]);
        }

        out.println(maxSum);
        out.flush();
        br.close();
        out.close();
    }
}

首先,我们定义状态 dp[i][j],表示从金字塔顶部到第 i 行第 j 列的最大路径和。

这里,ij 的范围都是从 0 开始的。

然后,我们需要找出状态转移方程(其实就是分析有多少种可能性)。

对于每一个位置 (i, j),我们可以从其上方 (i-1, j) 或者左上方 (i-1, j-1) 移动过来。

因此,到达当前位置的路径和就是上方或者左上方的路径和加上当前位置的值,我们选择其中的最大值作为当前位置的路径和。

具体来说,状态转移方程可以写成如下形式:

  • j == 0(即在每一行的最左边)时,只能从上方移动过来,所以 dp[i][j] = dp[i-1][j] + triangle[i][j]
  • j == i(即在每一行的最右边)时,只能从左上方移动过来,所以 dp[i][j] = dp[i-1][j-1] + triangle[i][j]
  • 0 < j < i 时,可以从上方或者左上方移动过来,所以 dp[i][j] = max(dp[i-1][j-1], dp[i-1][j]) + triangle[i][j]

最后,我们返回最后一行中的最大值,即为可能得到的最大的和

小结

动态规划(DP)的本质是对问题状态的定义和状态转移方程的定义。动态规划往往可以用来优化具有重叠子问题的递归算法(跟记忆化搜索相似)。

递归算法的特点是自顶向下,从一个问题开始,分解为多个子问题来求解。而动态规划则是自底向上,从最简单的子问题开始,逐步解决更复杂的子问题,直到得到原问题的解。

因此,对于一个可以用动态规划解决的问题,我们通常可以先尝试用递归的方法解决,然后找出递归中的重叠子问题,再使用动态规划的方法进行优化,避免重复计算。

但是需要注意的是,虽然所有的动态规划问题都可以从递归的角度来理解,但并不是所有的递归问题都可以用动态规划来优化。只有当递归问题具有“重叠子问题”和“最优子结构”时,才能使用动态规划进行优化。文章来源地址https://www.toymoban.com/news/detail-850549.html

到了这里,关于【题解 | 基础动态规划】:数字三角形的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 算法分析与设计-数字三角形问题(动态规划)(通俗易懂,附源码和图解,含时间复杂度分析)(c++)

    (一)题目 问题描述 给定一个由 n n n 行数字组成的数字三角形,如图所示。 试设计一个算法,计算从三角形的顶至底的一条路径,使该路径经过的数字总和最大。 算法设计 对于给定的由 n n n 行数字组成的数字三角形,计算从该三角形的顶至底的路径经过的数字和的最大值

    2023年04月10日
    浏览(45)
  • 力扣120. 三角形最小路径和(Java 动态规划)

    Problem: 120. 三角形最小路径和 Problem:64. 最小路径和 本题目可以看作是在上述题目的基础上改编而来,具体的思路: 1.记录一个int类型的大小的 n 乘 n n乘n n 乘 n 的数组(其中 n n n 为数组triangle的行数)用于记录 每一个当前阶段的最小路径和 2.大体上可以依据题意得出动态转移

    2024年01月22日
    浏览(42)
  • 蓝桥 卷“兔”来袭编程竞赛专场-03破解三角形密码 题解

    挑战介绍 三角形密码指的是将一串字符串按照正直角三角形的形状排列,传递的信息隐藏在每一行的最后一个字符,然后将所有的行的最后一个字符依次连接,就是需要传递的信息。 例如加密后的字符串是:我们爱的是蓝色的心桥 将加密字符串按照正直角三角形填充后如下

    2023年04月16日
    浏览(38)
  • 【数字三角形】

    题目描述 上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。 路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右 边的那个数。此外,向左下走

    2024年02月05日
    浏览(54)
  • 【数字三角形】(C++版)

    题目描述 上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和。 路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右 边的那个数。此外,向左下走

    2024年02月16日
    浏览(65)
  • AcWing 898. 数字三角形 (每日一题)

    像数组下标 出现 i-1 的,在循环的时候从 i=1 开始。 0x3f3f3f3f : 1061109567 Integer.MAX_VALUE : 2147483647 在选用 Integer.MAX_VALUE 时,很可能会出现 数据溢出 。 所以在用 Integer.MAX_VALUE 时 需要先取 MAX 再加 a[i][j]; 注:做 数字三角形 这题时, 初始化时需要注意一下边界 。 由于我们 状态计

    2024年02月11日
    浏览(41)
  • 数字三角形+包子凑数(蓝桥杯JAVA解法)

    题目描述 上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最大的和(路径上的每一步只可沿左斜线向下或右斜线向下走)。 输入描述 输入的第一行包含一个整数 N (1≤N≤

    2024年02月01日
    浏览(40)
  • 蓝桥杯第十一届省赛——数字三角形(python组)

    题目:数字三角形 【问题描述】: 上图给出了一个数字三角形。从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,你的任务就是找到最 大的和。 路径上的每一步只能从一个数走到下一层和它最近的左边的那个数或者右 边

    2023年04月10日
    浏览(48)
  • 湘大 XTU OJ 1148 三角形 题解(非常详细):根据题意朴素模拟+观察样例分析需要计算几轮 具体到一般

    1148 三角形 题目描述 给一个序列, 按下面的方式进行三角形累加,求其和值 。 比如序列为 1,2,3,4,5 输入 有多组样例。每个样例的第一行是一个整数N( 1≤N≤100 ),表示序列的大小, 如果N为0表示输入结束。这个样例不需要处理。 第二行是N个整数,每个整数处于[0,100]之间。

    2024年02月13日
    浏览(45)
  • 【算法挨揍日记】day03——双指针算法_有效三角形的个数、和为s的两个数字

       611. 有效三角形的个数 https://leetcode.cn/problems/valid-triangle-number/ 给定一个包含非负整数的数组  nums  ,返回其中可以组成三角形三条边的三元组个数。 本题是一个关于三角形是否能成立的题目,首先我们假设三角形的三边(a,b,c),我们要保证两边之和大于第三边    题

    2024年02月12日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包