因为之前没有怎么接触过算法,在赛码网上刷题,碰上了动态规划类的题目。正好借此机会系统的学习一下。
在哔哩哔哩上看算法视频,里面讲解了一道HDU上的题目,下面贴下题目描述:
ime Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 36261 Accepted Submission(s): 21659
Problem Description
在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的:
有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?
已经告诉你了,这是个DP的题目,你能AC吗?
|
Input
输入数据首先包括一个整数C,表示测试实例的个数,每个测试实例的第一行是一个整数N(1 <= N <= 100),表示数塔的高度,接下来用N行数字表示数塔,其中第i行有个i个整数,且所有的整数均在区间[0,99]内。
Output
对于每个测试实例,输出可能得到的最大和,每个实例的输出占一行。
Sample Input
1
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
Sample Output
30
解题思路:在不了解动态规划题目之前,应该首先想到的就是贪心吧,从顶想下,每次找最大的。经过测试,得到的结果为26。不如给出的样例结果大,贪心算法宣告失败。
递归的思路比较好想:顺着题目,我们从上往下看。第一层的节点没有什么好说的,他只有一个,但是到了第二层,节点就变成了两个。这就遇到了一个“选还是不选“的问题。假如我们选了第一个节点,而不选第二个节点。问一下自己,为什么不选第二个节点?当然是第一个节点的值大呗(注意了,上一段中我们已经说了,贪心的方法行不通,所以这里的”值大“代表经过处理后的值,怎么处理。。。下面讲)。同样的方法,继续进行第3,4,···n-1层的选择处理,到了第n层(递归的出口),选出较大的节点值,然后在进行回溯,就解决了。
经过递归思路的分析,注意到第n-1层依赖于第n层。所以我们只需将第n-1层各节点中子节点的最大值加上他们本身即可。如此向上处理。第一层的那个节点的值就是我们求的最大值。这里用的是递推的思想:从底向下分析。
代码:
import java.util.*;
public class Main {
public static int dp_numberta(int[][] arr,int n){
for(int i=n-2;i>=0;i--){
for(int j=0;j<=i;j++){
arr[i][j] = Math.max(arr[i+1][j],arr[i+1][j+1])+arr[i][j];
}
}
return arr[0][0];
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for(int k = 0;k<n;k++){
int N = sc.nextInt();
int[][] arr = new int[N][N];
for(int i=0;i<N;i++){
for (int j=0;j<=i;j++){
arr[i][j] = sc.nextInt();
}
}
System.out.println(dp_numberta(arr,N));
}
}
}