7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
(Figure 1)
5 7 3 8 8 1 0 2 7 4 4 4 5 2 6 5
30
/* http://bailian.openjudge.cn/practice/1163/ 1163:The Triangle 遞歸解法2:數字三角形的記憶遞歸型動歸程序 */ #include<iostream> #include<algorithm> #define MAX 101 using namespace std; int D[MAX][MAX]; int sum[MAX][MAX]; int n; int MaxSum(int i, int j) { if (sum[i][j] != -1)/*說明這個路徑的最大和已經算過了*/ { return sum[i][j]; } if (i == n) { sum[i][j] = D[i][j]; } else { int x = MaxSum(i + 1, j); int y = MaxSum(i + 1, j + 1); sum[i][j] = max(x, y) + D[i][j]; } return sum[i][j]; } int main() { int i, j; cin >> n; for (i = 0; i < n; i++) { for (j = 0; j <= i; j++) { cin >> D[i][j]; sum[i][j] = -1; } } cout << MaxSum(0, 0) << endl; return 0; }
/* The Triangle 遞歸轉成遞推 */ #include<iostream> #include<algorithm> using namespace std; int n; #define MAX 101 int D[MAX][MAX]; int maxsum[MAX][MAX]; int main() { int i, j; cin >> n; for (i = 0; i < n; i++) { for (j = 0; j <= i; j++) { cin >> D[i][j]; } } for (i = n - 1; i >= 0; i--) { for (j = 0; j <= n - 1; j++) { if (i == n - 1) { maxsum[i][j] = D[i][j]; } else { maxsum[i][j] = max(maxsum[i + 1][j], maxsum[i + 1][j + 1]) + D[i][j]; } } } cout << maxsum[0][0] << endl; return 0; }
/* The Triangle 遞歸轉成遞推 空間優化 用一維數組替代二維數組 進一步考慮,連maxSum 數組均可以不要,直接用 D 的第 n 行替代 maxSum 便可。 節省空間,時間複雜度不變 */ #include<iostream> #include<algorithm> using namespace std; int n; #define MAX 101 int D[MAX][MAX]; int *maxsum; int main() { int i, j; cin >> n; for (i = 0; i < n; i++) { for (j = 0; j <= i; j++) { cin >> D[i][j]; } } maxsum = D[n-1];/* maxSum 指向第 n 行 */ for (i = n - 2; i >= 0; i--) { for (j = 0; j <= n - 2; j++) { maxsum[j] = max(maxsum[j] ,maxsum[j + 1]) + D[i][j]; } } cout << maxsum[0] << endl; return 0; }
7 1 7 3 5 9 4 8
4
/* Dynamic Planning http://bailian.openjudge.cn/practice/2757 2757:最長上升子序列 思路:找子問題 1. 「求序列的前n 個元素的最長上升子序列的長度 是個子問題,但這樣分解子問題,不具備「無後效性」 2. 「求以ak( k=1, 2, 3…N )爲終點的最長上升子序列的長度」 */ #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 1010; int a[MAXN]; int maxLen[MAXN]; int main() { int N; cin >> N; for (int i = 1; i <= N; i++) { cin >> a[i]; maxLen[i] = 1; for (int i = 2; i <= N; ++i) { for (int j = 1; j < i; ++j) { if (a[i] > a[j]) {/*要遍歷子問題的最長子序列,j=1,2,3..., 有可能j=2 > j=3, 因此要記錄j=2時的最大值 ,防止j=3時,刷掉上一個實際的最優解 */ maxLen[i] = max(maxLen[i], maxLen[j] + 1); } } } } /* STL 函數*/ cout << *max_element(maxLen + 1, maxLen + N + 1); return 0; }
abcfbc abfcab programming contest abcd mnp
4 2 0
/* http://bailian.openjudge.cn/practice/1458 1458:Common Subsequence 公共子序列 */ #include<iostream> #include<cstring> #include<algorithm> using namespace std; char sz1[1000]; char sz2[1000]; int maxLen[1000][1000]; int main() { while (cin >> sz1 >> sz2) { int length1 = strlen(sz1); int length2 = strlen(sz2); int nTmp; int i, j; /* 邊界條件,若是一個字符串沒有字符,默認最長公共子序列爲0 */ for (i = 0; i <= length1; i++) maxLen[i][0] = 0; for (j = 0; j <= length2; j++) maxLen[0][j] = 0; for (i = 1; i <= length1; i++) { for (j = 1; j <= length2; j++) { if (sz1[i - 1] == sz2[j - 1]) { maxLen[i][j] = maxLen[i - 1][j - 1] + 1; } else { maxLen[i][j] = max(maxLen[i][j - 1], maxLen[i - 1][j]); } } } cout << maxLen[length1][length2] << endl; } return 0; }
給定n個1到9的數字,要求在數字之間擺放m個加號(加號兩邊必須有數字),使得所獲得的加法表達式的值最小,並輸出該值。例如,在1234中擺放1個加號,最好的擺法就是12+34,和爲36ios
2 123456 1 123456 4 12345
102 579 15
/* http://bailian.openjudge.cn/practice/4152/ 4152:最佳加法表達式 */ //By Guo Wei #include <iostream> #include <string> #include <cstring> #include<algorithm> using namespace std; struct BigInt { int num[110]; int len; BigInt operator+(const BigInt & n) { //重載+,使得 a + b在 a,b都是 BigInt變量的時候能成立 int ml = max(len, n.len); int carry = 0; //進位 BigInt result; for (int i = 0; i < ml; ++i) { result.num[i] = num[i] + n.num[i] + carry; if (result.num[i] >= 10) { carry = 1; result.num[i] -= 10; } else carry = 0; } if (carry == 1) { result.len = ml + 1; result.num[ml] = 1; } else result.len = ml; return result; } bool operator<(const BigInt & n) { if (len > n.len) return false; else if (len < n.len) return true; else { for (int i = len - 1; i >= 0; --i) { if (num[i] < n.num[i]) return true; else if (num[i] > n.num[i]) return false; } return false; } } BigInt() { len = 1; memset(num, 0, sizeof(num)); } BigInt(const char * n, int L) { //由長度爲L的char數組構造大整數。n裏面的元素取值範圍從 1-9。 memset(num, 0, sizeof(num)); len = L; for (int i = 0; n[i]; ++i) num[len - i - 1] = n[i] - '0'; } }; ostream & operator <<(ostream & o, const BigInt & n) { for (int i = n.len - 1; i >= 0; --i) o << n.num[i]; return o; } const int MAXN = 60; char a[MAXN]; BigInt Num[MAXN][MAXN];//Num[i][j]表示從第i個數字到第j個數字所構成的整數 BigInt V[MAXN][MAXN]; //V[i][j]表示i個加號放到前j個數字中間,所能獲得的最佳表達式的值。 int main() { int m, n; BigInt inf; //無窮大 inf.num[MAXN - 2] = 1; inf.len = MAXN - 1; while (cin >> m) { cin >> a + 1; n = strlen(a + 1); for (int i = 1; i <= n; ++i) for (int j = i; j <= n; ++j) { Num[i][j] = BigInt(a + i, j - i + 1); } for (int j = 1; j <= n; ++j) { V[0][j] = BigInt(a + 1, j); } for (int i = 1; i <= m; ++i) { for (int j = 1; j <= n; ++j) { if (j - 1 < i) V[i][j] = inf; else { BigInt tmpMin = inf; for (int k = i; k < j; ++k) { BigInt tmp = V[i - 1][k] + Num[k + 1][j]; if (tmp < tmpMin) tmpMin = tmp; } V[i][j] = tmpMin; } } } cout << V[m][n] << endl; } return 0; }