1. 问题描述
有一个像这样的数字三角形:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
从顶点开始,每个数字向下层走只能有左下和右下两个方向,求出到达最后一行时最大的路径之和。
Input
第1 行是数字三角形的行数n,1<= n <=100。
接下来n行是数字三角形各行中的数字。所有数字在0---99之间。
比如Input是:
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
则output是30。
2. 问题求解
这是一个典型的动态规划求解问题,因为它符合动态规划所能解决的问题的性质:
最优子结构性质
子问题重叠性
看到这个题目,很容易想起多段图的那个题目,其实道理真的是一样的,唯一的区别就是:一个是从一些顶点到一个终点求最小值;一个是一个起点到一些点求最大值。
所以状态和转移方程都可以模仿多段图的解法:
\[f(i,j) = \max \{ f(i - 1,j - 1),f(i - 1,j)\} + {C_{ij}}\]
其中i表示该点所在三角形的行数(行数从0开始算),j表示该点所在某行的第几个,也就是列数(列数从0开始计算)。
注意:转移方程中的i,j在代码计算的时候不能越界。所以每一行的两端的数字的f函数要单独计算,只有一种决策才能到达它们。
3. 代码实现
#define MAX 100 #define getMax(x,y) (x>y ? x : y) #include <stdio.h> void main(void) { freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); //初始化数组的元素全部为0 int path[MAX][MAX] = {0}; int dist[MAX][MAX] = {0}; //为三角形赋值 int i = 0; int j = 0; int n = 0; //三角形的行数 scanf("%d", &n); for(i= 0; i < n; i++) { for(j = 0; j <= i; j++) { scanf("%d", &path[i][j]); } }//for //为了防止转移方程越界,每行的开头和结尾首先算出最长路径 dist[0][0] = path[0][0]; for(i = 1; i < n; i++) { dist[i][0] = dist[i-1][0] + path[i][0]; }//for for(i = 1; i < n; i++) { dist[i][i] = dist[i-1][i-1] + path[i][i]; } //计算出中间每个节点的最长路径 for(i = 2; i < n; i++) { for(j = 1; j < i; j++) { dist[i][j] = getMax(dist[i-1][j-1], dist[i-1][j]) + path[i][j]; } } //找到最长的路径 int maxSum = 0; for(j = 0; j < n; j++) { if(maxSum < dist[n-1][j]) { maxSum = dist[n-1][j]; } }//for printf("%d", maxSum); fclose(stdin); fclose(stdout); return; }
测试数据:
5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
时间: 2024-10-01 06:07:41