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; }