题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2084
经典的DP入门题。
最近学起DP,做回这道题目,用的是自顶向上的方法来求解,发现代码很长,不过时间短了,这应该就是传说中的“以空间换时间”的说法吧。个人觉得,这比较符合人的思考模式,不过真的很繁琐,由于不知道最后一行中最大和的具体位置,还要比较找出。
状态转移方程是(设f(i, j)为三角形上从点(i,j)出发向下走的最大和路径, a(i, j)表示原始输入的第 i 行第 j 列的数 :
f(i, j) = a(i, j) + max{f(i-1, j-1), f(i-1, j)} i != j (每行里除第一和最后的处于中间位置的数
a(i, j)+ f(i-1, j) j = 0 (每行里的第一个数)
a(i, j) + f(i-1, j-1) j = i (每行里的最后一个数)
1 #include <iostream> 2 using namespace std; 3 4 int main() 5 { 6 int c, i, j, n, a[105][105], maxsum; 7 while (scanf("%d", &c) != EOF) 8 { 9 while (c--) 10 { 11 scanf("%d", &n); 12 for (i = 0; i < n; i++) 13 { 14 for (j = 0; j <= i; j++) 15 scanf("%d", &a[i][j]); 16 } 17 for (i = 1; i < n; i++) 18 { 19 for (j = 0; j <= i; j++) 20 { 21 if (j == 0) //每行的第一个数只能从它的正上一行+当前行的数 22 { 23 a[i][j] = a[i-1][j] + a[i][j]; 24 } 25 else if (i == j) //每行的最后一个数只能从它的左上一行+当前行的数 26 a[i][j] = a[i-1][j-1] + a[i][j]; 27 else 28 { 29 if (a[i-1][j] > a[i-1][j-1]) //上一行的左边的数和上一行正对着的数比较 30 a[i][j] = a[i-1][j] + a[i][j]; 31 else 32 a[i][j] = a[i-1][j-1] + a[i][j]; 33 } 34 } 35 } 36 maxsum = -100; 37 for (j = 0; j <= n-1; j++) 38 if (maxsum < a[n-1][j]) 39 maxsum = a[n-1][j]; 40 printf("%d\n", maxsum); 41 } 42 } 43 return 0; 44 }
自底向上的求法:
(连特殊位置的判断都不用考虑了,而且保证最后输出的a[0][0]一定是最大的)
1 #include <iostream> 2 using namespace std; 3 4 int main() 5 { 6 int c, i, j, n, a[105][105]; 7 while (scanf("%d", &c) != EOF) 8 { 9 while (c--) 10 { 11 scanf("%d", &n); 12 for (i = 0; i < n; i++) 13 { 14 for (j = 0; j <= i; j++) 15 scanf("%d", &a[i][j]); 16 } 17 for (i = n - 2; i >= 0; i--) 18 { 19 for (j = 0; j <= i; j++) 20 { 21 if (a[i+1][j] > a[i+1][j+1]) 22 a[i][j] = a[i+1][j] + a[i][j]; 23 else 24 a[i][j] = a[i+1][j+1] + a[i][j]; 25 } 26 } 27 printf("%d\n", a[0][0]); 28 } 29 } 30 return 0; 31 }