思想
动态规划是一种用来解决一类最优化问题的算法思想过。
它将一个复杂的问题分解为若干个子问题,通过综合子问题的最优解来得到原问题的解。
概念
如果一问题可以被分解为若干个子问题,且这些子问题会重复出现,那么就称这个问题拥有重叠子问题
如果一问题可以由其子问题的最优解有效地构造出来,那么称这个问题拥有最优子结构。
一问题必须拥有重叠子问题和最优子结构,才能使用动态规划去求解。
动态规划必须设计一个无后效性的状态以及相应的状态转移方程。
区别
分治法与动态规划:分治法的子问题不重叠,动态规划的子问题重叠。归并和快排都是分治法。另外分治法解决的问题不一定是最优化问题,而动态规划解决的问题一定是最优化问题。
贪心与动态规划:贪心与动态规划都要求原问题有最优子结构,贪心法不会考虑所有子问题,而是以一种单链的流水方式进行。动态规划
会考虑所有的子问题,并选择继承能得到最优结果的那个。
数塔问题
#include <iostream>
#include <algorithm>
using namespace std;
/************************************************************************/
/* 数塔问题 */
/************************************************************************/
const int N = 50;//为了算法写起来简单,这里定义一个足够大的数用来存储数据(为了避免运算过程中动态申请空间,这样的话算法看起来比较麻烦,这里只是为了算法看起来简单)
int data[N][N];//存储数塔原始数据
int dp[N][N];//存储动态规划过程中的数据
int n;//塔的层数
/*动态规划实现数塔求解*/
void tower_walk()
{
// dp初始化
for (int i = 0; i < n; ++i)
{
dp[n - 1][i] = data[n - 1][i];
}
int temp_max;
for (int i = n - 1; i >= 0; --i)
{
for (int j = 0; j <= i; ++j)
{
// 使用递推公式计算dp的值
temp_max = max(dp[i + 1][j], dp[i + 1][j + 1]);
dp[i][j] = temp_max + data[i][j];
}
}
}
/*打印最终结果*/
void print_result()
{
cout << "最大路径和:" << dp[0][0] << '\n';
int node_value;
// 首先输出塔顶元素
cout << "最大路径:" << data[0][0];
int j = 0;
for (int i = 1; i < n; ++i)
{
node_value = dp[i - 1][j] - data[i - 1][j];
/* 如果node_value == dp[i][j]则说明下一步应该是data[i][j];如果node_value == dp[i][j + 1]则说明下一步应该是data[i][j + 1]*/
if (node_value == dp[i][j + 1]) ++j;
cout << "->" << data[i][j];
}
cout << endl;
}
int main()
{
cout << "输入塔的层数:";
cin >> n;
cout << "输入塔的节点数据(第i层有i个节点):\n";
for (int i = 0; i < n; ++i)
{
for (int j = 0; j <= i; ++j)
{
cin >> data[i][j];
}
}
tower_walk();
print_result();
}
最大连续子序列和(A1007)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SswmagLr-1585618588926)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330134052382.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3vDGtqZK-1585618588926)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330134032263.png)]
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxN = 10010;
int dp[maxN];
int prec[maxN];
int value[maxN];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> value[i];
dp[i] = value[i];
prec[i] = i;
}
for (int i = 1; i < n; i++) {
if (dp[i - 1] + value[i] > dp[i]) {
dp[i] = dp[i - 1] + value[i];
prec[i] = prec[i - 1];
}
}
int max = -1;
int maxIndex = -1;
for (int i = 0; i < n; i++) {
if (dp[i] > max) {
max = dp[i];
maxIndex = i;
}
}
if(max >= 0) {
cout << max << " " << value[prec[maxIndex]] << " " << value[maxIndex] << endl;
}else{
cout << 0 << " " << value[0] << " " << value[n-1] << endl;
}
return 0;
}
最大不下降子序列
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NP7EODYh-1585618588927)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330134152808.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DsFO08p5-1585618588928)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330134205230.png)]
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxN = 205;
const int maxN2 = 10020;
int num[maxN];
int dp[maxN2];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> num[i];
}
fill(dp, dp + maxN2, 1);
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
if (num[i] > num[j]) {
dp[i] = max(dp[j] + 1, dp[i]);
}
}
}
int tempmax = 0;
for (int i = 0; i < n; i++) {
tempmax = max(tempmax, dp[i]);
}
cout << tempmax << endl;
return 0;
}
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxN = 205;
const int maxN2 = 10020;
int order[maxN];
int color[maxN2];
int dp[maxN2];
int main() {
int n;
cin >> n;
cin >> n;
int temp;
fill(order, order + maxN, -1);
for (int i = 0; i < n; i++) {
cin >> temp;
order[temp] = i;
}
int l;
cin >> l;
for (int i = 0; i < l; i++) {
cin >> temp;
color[i] = temp;
}
fill(dp, dp + maxN2, 1);
int tempmax = 1;
for (int i = 0; i < l; i++) {
if (order[color[i]] > -1) {
for (int j = 0; j < i; j++) {
if (order[color[i]] >= order[color[j]]) {
dp[i] = max(dp[j] + 1, dp[i]);
}
}
} else {
dp[i] = -100;
}
}
for (int i = 0; i < l; i++) {
tempmax = max(tempmax, dp[i]);
}
cout << tempmax << endl;
return 0;
}
最长公共子序列(LCS)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QrRcjJjz-1585618588928)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330141238941.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ps8DFcYg-1585618588928)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330141253290.png)]
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxN = 205;
const int maxN2 = 10020;
int a[maxN];
int b[maxN2];
int dp[maxN][maxN2];
int main() {
int n;
cin >> n;
cin >> n;
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int l;
cin >> l;
for (int i = 1; i <= l; i++) {
cin >> b[i];
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= l; j++) {
if(a[i] == b[j]){
dp[i][j] = dp[i-1][j-1]+1;
}else{
dp[i][j] = max(dp[i][j-1], dp[i][j-1]);
}
}
}
cout << dp[n][l] << endl;
return 0;
}
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxN = 205;
const int maxN2 = 10020;
int a[maxN];
int b[maxN2];
int dp[maxN][maxN2];
int main() {
int n;
cin >> n;
cin >> n;
memset(dp, 0, sizeof(dp));
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
int l;
cin >> l;
for (int i = 1; i <= l; i++) {
cin >> b[i];
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= l; j++) {
if(a[i] == b[j]){
dp[i][j] = max(dp[i-1][j-1]+1,dp[i][j-1]+1);
}else{
dp[i][j] = max(dp[i][j-1], dp[i-1][j]);
}
}
}
cout << dp[n][l]<< endl;
return 0;
}
最大回文子串
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s4cqw4bd-1585618588929)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330144523899.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QgrtSkHu-1585618588929)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330144538627.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NgrT4SzE-1585618588929)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330144553866.png)]
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxN = 1010;
int dp[maxN][maxN];
int main()
{
string str;
getline(cin, str);
int ans = 1;
int len = str.size();
for(int i = 0; i < len; i++){
dp[i][i] = 1;
if(i < len - 1){
if(str[i] == str[i+1]){
dp[i][i+1] = 1;
ans = 2;
}
}
}
for(int L = 3; L <= len; L++){
for(int i = 0; i + L - 1 < len; i++){
int j = i + L - 1;
if(str[i] == str[j] && dp[i+1][j-1] == 1){
dp[i][j] = 1;
ans = L;
}
}
}
cout << ans << endl;
return 0;
}
背包问题(一维数组优化过)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EMMDLV2D-1585618588930)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330145319131.png)]
01背包问题
for (i = 1; i <= n; i++){
for (v = V; v >= w[i] ; v--){
dp[v] = max(dp[v], dp[v-w[i]]+c[i]);
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fdo2dFM7-1585618588930)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330145331825.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OEeIWlos-1585618588931)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330145340904.png)]
完全背包问题
for (i = 1; i <= n; i++){
for (v = w[i]; v <= V; v++){
dp[v] = max(dp[v], dp[v-w[i]]+c[i]);
}
}
多重背包问题
即每个物品不能是无限个,最多只能k个,这里可将问题拆分成为k个01背包问题。
DAG最长路
固定起点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S5ZNeM9U-1585618588931)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330155658787.png)]
固定终点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S7qvTZAh-1585618588931)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330155711850.png)]
总结
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gy4PqfzD-1585618588933)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330155604947.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xPkssTo9-1585618588933)(/Users/tinysean/Library/Application Support/typora-user-images/image-20200330155616923.png)]