Description
,有一個群島,共分為若干層,第1層有一個島嶼,第2層有2個島嶼,......,第n層有n個島嶼。每個島上都有一塊寶,其價值是一個正整數(圖中圓圈中的整數)。尋寶者只允許從第一層的島嶼進入,從第n層的島嶼退出,不能後退,他能收集他所經過的所有島嶼上的寶貝。但是,從第i層的島嶼進入第i+1層的島嶼時,有且僅有有2條路徑。你的任務是:對於給定的群島和島上寶貝的價值,計算一個拾寶者行走一趟所能收集寶貝的最大價值。
Input
第一行是一個整數n,在[2,20]之間,表示要輸入的案例的數量。後面緊跟n個案例。對每個案例,第一行是一個整數mi,在[2, 50]之間,表示該案例中島嶼的層數,後面緊跟mi*(mi+1)/2行,每行有1個整數,表示響應的島嶼上寶貝的價值,每個數值的範圍是[1, 1000]。注意:如果mi是4,而後面緊跟的10行的元素分別是5, 2, 1, 4, 7, 9, 4, 2, 3, 5,則表示第一層的資料是5;第2層的資料是2, 1;第3層的資料是4, 7, 9;第4層的資料是4, 2, 3, 5。
Output
對每一個案例,用一行輸出一個整數,表示輸出拾寶者所能收集寶貝的最大價值。
Sample Input
2
4
5
2
1
4
7
9
2
2
3
5
2
1
2
3
Sample Output
20
4
方法:動態規劃。把當前位置(i,j)看成一個狀態,設指標函數d(i,j)為從格子(i,j)出發時能得到的最大和,原問題的解為d(1,1)。容易得出狀態轉移方程d(i,j) = a(i,j) + max{d(i+1,j), d(i+1, j+1)}
方法一:遞迴計算(時間複雜度O(2^n),會逾時)
1 #include <cstdio> 2 #include <algorithm> //for max(val1,val2) 3 #include <iostream> 4 using namespace std; 5 int n; 6 int a[51][51]; 7 int main() 8 { 9 int t;10 scanf("%d", &t);11 while (t--)12 {13 int i,j;14 scanf("%d",&n);15 for(i=1;i<=n;i++)16 for(j=1;j<=i;j++)17 scanf("%d",&a[i][j]);18 int d(int, int);19 printf("%d\n", d(1, 1));20 }21 system("pause");22 return 0;23 }24 25 int d(int i, int j)26 {27 if (i == n)28 return a[i][j] + 0;29 else30 return a[i][j] + max(d(i+1, j), d(i+1, j+1));31 }
法2:遞推計算(時間複雜度O(n^2),需要輔助數組d)
1 #include <iostream> 2 #include <algorithm> //for max(val1, val2) 3 #include <cstdio> 4 using namespace std; 5 int n; 6 int a[51][51]; 7 int d[51][51]; 8 int main() 9 {10 int t;11 scanf("%d", &t);12 while (t--)13 {14 int i, j;15 scanf("%d", &n);16 for (i = 1; i <= n; ++i)17 for (j = 1; j <= i; ++j)18 scanf("%d", &a[i][j]);19 for (i = 1; i <= n; ++i)20 d[n][i] = a[n][i]; //邊界處理21 for (i = n - 1; i >= 1; --i) //逆序計算22 for (j = 1; j <= i; ++j)23 d[i][j] = a[i][j] + max(d[i+1][j], d[i+1][j+1]);24 printf("%d\n", d[1][1]);25 }26 system("pause");27 return 0;28 }
法3:記憶化搜尋(遞迴函式,O(n^2))
1 #include <iostream> 2 #include <algorithm> //for max(val1, val2) 3 #include <cstdio> 4 #include <cstring> //for *memset(s, c, n) 5 using namespace std; 6 int n; 7 int a[51][51]; 8 int d[51][51]; 9 int main()10 {11 int t;12 scanf("%d", &t);13 while (t--)14 {15 memset(d, -1, sizeof(d)); //初始化數組d為-1 16 int i, j;17 scanf("%d", &n);18 for (i = 1; i <= n; ++i)19 for (j = 1; j <= i; ++j)20 scanf("%d", &a[i][j]);21 int f(int, int);22 printf("%d\n", f(1, 1));23 }24 system("pause");25 return 0;26 }27 28 int f(int i, int j)29 {30 if (d[i][j] >= 0) //由於每個數範圍為[1,1000],d[i][j]初始化為-1,可以根據d[i][j] >= 0判斷是否已經被計算過31 return d[i][j];32 if (i == n)33 return a[i][j] + 0;34 else35 return d[i][j] = a[i][j] + max(f(i+1,j), f(i+1, j+1)); //儲存d[i][j]並返回36 }
本菜花了幾個小時整理的,在devc下編譯通過。