动态规划

思想

动态规划是一种用来解决一类最优化问题的算法思想过。

它将一个复杂的问题分解为若干个子问题,通过综合子问题的最优解来得到原问题的解。

概念

如果一问题可以被分解为若干个子问题,且这些子问题会重复出现,那么就称这个问题拥有重叠子问题

如果一问题可以由其子问题的最优解有效地构造出来,那么称这个问题拥有最优子结构。

一问题必须拥有重叠子问题最优子结构,才能使用动态规划去求解。

动态规划必须设计一个无后效性的状态以及相应的状态转移方程。

区别

分治法与动态规划:分治法的子问题不重叠,动态规划的子问题重叠。归并和快排都是分治法。另外分治法解决的问题不一定是最优化问题,而动态规划解决的问题一定是最优化问题。

贪心与动态规划:贪心与动态规划都要求原问题有最优子结构,贪心法不会考虑所有子问题,而是以一种单链的流水方式进行。动态规划

会考虑所有的子问题,并选择继承能得到最优结果的那个。

数塔问题

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

Favorite Color Stripe A1045

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

Favorite Color Stripe A1045

#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]);
		}
	}

Find More Coins(A1068)

最小邮票数 北大

整数拆分 清华

多重背包问题

即每个物品不能是无限个,最多只能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)]

应用练习

放水果 北大

整数拆分 北大

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值