第15章动态规划------算法导论
15.1钢条切割
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<ctime> #include<string> using namespace std; int p[1000]{ 0,1,5,8,9,10,17,17,20,24,30 };//钢条价格。长度i的价格为p[i] int ordinary(int *p, int n)//递归法 { if (n == 0) return 0; else { int q = -1; for (int i = 1; i <= n; ++i) { q = max(p[i] + ordinary(p, n - i), q); } return q; } } int top_down_memory(int *p, int n)//动态规划 带备忘的自顶向下法 与递归法类似,只是结果存储起来了 { static int b[1000]; if (n == 0) return 0; if (b[n] != 0) { return b[n]; } else { int q = -1; for (int i = 1; i <= n; ++i) { q = max(p[i] + top_down_memory(p, n - i), q); } b[n] = q; return q; } } int bottom_up_method(int *p, int n)//动态规划 自底向上 把子结果都先求出来,再求总结果 { static int b[1000]; for (int i = 1; i <= n; ++i) { int q = -1; for (int j = 1; j <= i; ++j) { q = max(q, p[j] + b[i - j]); } b[i] = q; } return b[n]; } int bottom_up_method_result(int *p, int n)//动态规划 自底向上 把子结果都先求出来,再求总结果 同时把如何切割求出来 { static int b[1000]; static int s[1000];//切割方案 for (int i = 1; i <= n; ++i) { int q = -1; int ss = -1; for (int j = 1; j <= i; ++j) { if (q < p[j] + b[i - j]) { q = p[j] + b[i - j]; ss = j; } } s[i] = ss; b[i] = q; } return b[n]; } int main() { int n; clock_t start; while (cin >> n) { start = clock(); cout << ordinary(p, n); cout << "ordinary:" << double(clock() - start) <<endl; start = clock(); cout << bottom_up_method_result(p, n); cout << "bottom_up_method_result:" << double(clock() - start) << endl; start = clock(); cout << top_down_memory(p, n); cout << "top_down_memory:" << double(clock() - start) << endl; } }
结果:前面是结果,后面是函数运行时间
25 73ordinary:4497 73bottom_up_method_result:0 73top_down_memory:1
15.2矩阵链乘法
#define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<algorithm> #include<ctime> #include<string> using namespace std; int p[1000]{ 0, 30,35,15,5,10,20,25,99,65,32,45,79,96,15 }; #define N 14 int ordinary(int *p, int a, int b)//递归法 { if (a == b)return 0; if (a + 1 == b)return p[a] * p[b] * p[b + 1]; int min = INT_MAX; for (int i = a; i < b; ++i) { if (min >(ordinary(p, a, i) + ordinary(p, i + 1, b) + p[a] * p[i + 1] * p[b + 1])) min = ordinary(p, a, i) + ordinary(p, i + 1, b) + p[a] * p[i + 1] * p[b + 1]; } return min; } int top_down_memory(int *p, int a, int b)//动态规划 带备忘的自顶向下法 与递归法类似,只是结果存储起来了 { static int dd[1000][1000]; if (dd[a][b])return dd[a][b]; if (a == b)return 0; if (a + 1 == b)return p[a] * p[b] * p[b + 1]; int min = INT_MAX; for (int i = a; i < b; ++i) { if (min >(top_down_memory(p, a, i) + top_down_memory(p, i + 1, b) + p[a] * p[i + 1] * p[b + 1])) min = top_down_memory(p, a, i) + top_down_memory(p, i + 1, b) + p[a] * p[i + 1] * p[b + 1]; } dd[a][b] = min; return min; } static int s[1000][1000]; int bottom_up_method(int *p, int a, int b)//动态规划 自底向上 把子结果都先求出来,再求总结果 { static int q[1000][1000]; for (int i = 2; i <= b; ++i) for (int j = 1; j <= b - i + 1; ++j) { for (int k = 1; k < i; ++k) { if (q[j][i] != 0 && q[j][i] > q[j][k] + q[j + k][i - k] + p[j] * p[j + k] * p[i + j]) { q[j][i] = q[j][k] + q[j + k][i - k] + p[j] * p[j + k] * p[i + j]; s[j][i + j - 1] = k + j - 1; } if (q[j][i] == 0) { q[j][i] = q[j][k] + q[j + k][i - k] + p[j] * p[j + k] * p[i + j]; s[j][i + j - 1] = k + j - 1; } } } return q[1][b]; } void print_result(int s[][1000], int i, int j) { if (i == j) cout << "A" << i; else { cout << "("; print_result(s, i, s[i][j]); print_result(s, s[i][j] + 1, j); cout << ")"; } } int main() { int n=N; clock_t start; start = clock(); cout << ordinary(p, 1, n-1);//递归法; cout << "ordinary:" << double(clock() - start) << " " << endl; start = clock(); cout << top_down_memory(p, 1, n - 1) ; cout << "top_down_memory:" << double(clock() - start) << " " << endl; start = clock(); cout << bottom_up_method(p, 1, n - 1) ; cout << "bottom_up_method:" << double(clock() - start) << " " << endl; start = clock(); print_result(s, 1, n - 1); cout << endl; return 0; }
结果:前面是结果,后面是函数运行时间
138670ordinary:406 138670top_down_memory:1 138670bottom_up_method:0 ((A1(A2A3))(((((((((A4A5)A6)A7)A8)A9)A10)A11)A12)A13)) 请按任意键继续. . .
15.4最长公共子序列
#include<iostream> #include<vector> #include<set> #include<string> #include<ctime> #include<algorithm> using namespace std; void subset2(const char *a, int n, vector<string> &sub2, string temp = string(), int t = 0)//产生子串,上一篇文章有介绍 { if (t == n) { sub2.push_back(temp); return; } subset2(a, n, sub2, temp, t + 1); temp += (a[t]); subset2(a, n, sub2, temp, t + 1); } int violence(string a, string b)//暴力子串匹配 { vector<string> sub2; subset2(a.c_str(), a.size(), sub2); int max_s = 0; for (int i = 0; i < sub2.size(); ++i) { int k = 0; for (int j = 0; j < b.size() && k < sub2[i].size(); ++j) { if (b[j] == sub2[i][k]) ++k; } if (k == sub2[i].size()) max_s = max(max_s, k); } return max_s; } int ordinary(string a, string b, int ii, int jj)//递归法 { if (ii == 0 || jj == 0)return 0; if (a[ii] == b[jj]) { return ordinary(a, b, ii - 1, jj - 1) + 1; } return max(ordinary(a, b, ii, jj - 1), ordinary(a, b, ii - 1, jj)); } int top_down_memory(string a, string b, int ii, int jj)//动态规划 带备忘的自顶向下法 与递归法类似,只是结果存储起来了 { static int p[1000][1000]; if (p[ii][jj])return p[ii][jj]; if (ii == 0 || jj == 0)return 0; if (a[ii] == b[jj]) { p[ii][jj] = top_down_memory(a, b, ii - 1, jj - 1) + 1; return p[ii][jj]; } p[ii][jj] = max(top_down_memory(a, b, ii, jj - 1), top_down_memory(a, b, ii - 1, jj)); return p[ii][jj]; } int bottom_up_method(string a, string b)//动态规划 自底向上 把子结果都先求出来,再求总结果 { int **p = new int *[a.size() + 1]; for (int i = 0; i < a.size() + 1; ++i) p[i] = new int[b.size() + 1]; for (int i = 0; i < a.size() + 1; ++i) for (int j = 0; j < b.size() + 1; ++j) p[i][j] = 0; for (int i = 0; i < a.size(); ++i) for (int j = 0; j < b.size(); ++j) { if (a[i] == b[j]) p[i + 1][j + 1] = p[i][j] + 1; else p[i + 1][j + 1] = max(p[i][j + 1], p[i + 1][j]); } //for (int i = 0; i < a.size() + 1; ++i) //{ // for (int j = 0; j < b.size() + 1; ++j) // cout<<p[i][j]<<" "; // cout << endl; //} return p[a.size()][b.size()]; } int main() { string a, b; clock_t start; cin >> a >> b; start = clock(); cout << violence(a, b); cout << "violence:" << double(clock() - start) << " " << endl; start = clock(); cout << bottom_up_method(a, b); cout << "bottom_up_method:" << double(clock() - start) << " " << endl; start = clock(); cout << ordinary(a, b, a.size(), b.size()); cout << "ordinary:" << double(clock() - start) << " " << endl; start = clock(); cout << top_down_memory(a, b, a.size(), b.size()); cout << "top_down_memory:" << double(clock() - start) << " " << endl; start = clock(); }
结果:前面是结果,后面是函数运行时间
{1,3,4,5,6,7,7,8} {3,5,7,4,8,6,7,8,2} 12violence:4400 12bottom_up_method:1 12ordinary:5798 12top_down_memory:7 请按任意键继续. . .