写了这么久程序,总是卡在动态规划,这次,准备集中攻克一下
如果我们能够保存已解决的子问题的答案,而在需要时简单查一下,这样我们就可以避免大量的重复计算,从而得到多项式时间的算法。
为了实现上述算法,我们用一个数组来记录所有已解决的子问题的答案,无论子问题以后是否被用到,只要它被计算过,就将其存入数组中,这种方法在程序设计中被称为动态规划。
由浅到难进行攻克,选择【牛客网——数字三角形】作为第一题。同时也是IOI’94年的题
【题目描述】
如下所示为一个数字三角形:
73 8
8 1 0
2 7 4 4
4 5 2 6 5
请编一个程序计算从顶到底的某处的一条路径,使该路径所经过的数字的总和最大
每一步可沿直线向下或右斜线向下走。
1<三角形行数≤100
三角形中的数字为整数0,1,。。。,99
【输入描述】
输入包含多组。每组数据的第一行包含一个正整数n(1≤n≤100),代表三角形的层数。
紧接着有n行数字,第i(1≤i≤n)行包含i个自然数。
【输出描述】
对应每组数据,输出最大的和。
看到了题目要求是会输入多组,哎。。。。怎么输入多组呢?
C++解决方法:
int n;
while (cin >> n)
{
//执行的方法
}
JAVA解决方法:
Scanner sc=new Scanner(System.in);
while(sc.hasNext()) {
int n = sc.nextInt();
//执行的方法
}
分析:
由于某个点只可能走到它的下方或斜下方(如图8向下到2,向斜下到7)。也可以这么看,7只能由8或1到达。
7
3 8
8 1 0
↓↘↓
2 7 4 4
4 5 2 6 5
因此,最优路径必定与其左上方或正上方两个位置的最优路径有关。(7的最优路径必定于8或1的最优路径有关)
用二维数组a来记录数字三角形中的数,a[ i , j ]表示数字三角形中第i行的第j个数。
用二维数组m记录每个位置的最优路径的数字总和。
计算数组m用逐行递推的方法实现。
关键公式:m[ i , j ] = a[ i , j ] + max{ m[ i+1 , j ] , m[ i+1 ,j+1]}
例:
a[ 2 , 0] = 8
a[ 3 , 0] = 2 a[ 3 , 1 ] = 7
m[ 2 , 0] = a[2 , 0 ] + max{ m[ 3 , 0 ] , m[ 3 , 1 ]}
JAVA代码:
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
int n;//行数
int[][] a;//存放三角形
int[][] m;//存放运算结果
Scanner sc = new Scanner(System.in);
while(sc.hasNext())
{
n = sc.nextInt();
a = new int[n][n];
m = new int[n][n];
for (int i7=0;i7<n;i7++)
Arrays.fill(m[i7], 0);
for(int i1=0;i1<n;i1++)
{
for(int i2=0;i2<=i1;i2++)
{
a[i1][i2]=sc.nextInt();
}
}
for(int i3=0;i3<n;i3++)
{
m[n-1][i3] = a[n-1][i3];
}
if(n>1)
{
for(int i=n-2;i>=0;i--)
{
for(int j=0;j<=i;j++)
{
if(m[i+1][j]>m[i+1][j+1])
{
m[i][j]=a[i][j]+m[i+1][j];
}
else
{
m[i][j]=a[i][j]+m[i+1][j+1];
}
}
}
}
System.out.println(m[0][0]);
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/686dd8d5312e374f1ce4f09c57368226.png)