C++学习计划 - 动态规划

学习目标

  • 掌握背包 DP
  • 掌握最大连续子段和、最长上升子序列、最长公共子序列等问题
  • 掌握区间 DP、棋盘 DP、金字塔 DP 等其他 DP

学习时间

  • 周三晚上 18:00~21:00

DP 类型题目

数字三角形 - 金字塔 DP

题目内容

观察下面的数字金字塔。

写一个程序来查找从最高点到底部任意处结束的路径,使路径经过数字的和最大。每一步可以走到左下方的点也可以到达右下方的点。

        7 
      3   8 
    8   1   0 
  2   7   4   4 
4   5   2   6   5 

在上面的样例中,从 7 → 3 → 8 → 7 → 5 7\rightarrow3\rightarrow8\rightarrow7\rightarrow5 73875 的路径产生的答案最大。

题解

思路:金字塔 DP,状态转移方程为:
d p [ i ] [ j ] = max ⁡ ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − 1 ] ) + a [ i ] [ j ] dp[i][j]=\max(dp[i-1][j],dp[i-1][j-1])+a[i][j] dp[i][j]=max(dp[i1][j],dp[i1][j1])+a[i][j]
代码:

#include <bits/stdc++.h>
using namespace std;
long long n, a[1005][1005], dp[1005][1005];
int main() {
   
   
    cin >> n;
    for (int i = 1; i <= n; i++) for (int j = 1; j <= i; j++) cin >> a[i][j];
    dp[1][1] = a[1][1];
    for (int i = 2; i <= n; i++) for (int j = 1; j <= i; j++) dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - 1]) + a[i][j];
    long long ans = 0;
    for (int i = 1; i <= n; i++) ans = max(ans, dp[n][i]);
    cout << ans << endl;
    return 0;
}

骨头收藏家 - 01背包

题目内容

许多年前,在泰迪的家乡有一个人,他被称为 “骨头收藏家” 。这个人喜欢收集各种各样的骨头,比如狗的,牛的,他也去了坟墓…… .

收集骨头的人有一个体积为 V V V 的大袋子,在他收集的过程中有很多骨头,很明显,不同的骨头有不同的价值,不同的体积,现在给出每根骨头在他的过程中的价值,你能计算出收集骨头的人能得到的最大总价值吗?

题解

思路:01背包,状态转移方程为:
d p [ j ] = d p [ j − w [ i ] ] + v [ i ] dp[j]=dp[j-w[i]]+v[i] dp[j]=dp[jw[i]]+v[i](一维 DP 数组更省空间)

代码:

#include <bits/stdc++.h>
using namespace std;
int n, V, dp[1005], w[1005], v[1005];
int main() {
   
   
    int t;
    cin >> t;
    while (t--) {
   
   
        cin >> n >> V;
        for (int i = 1; i <= n; i++) cin >> v[i];
        for (int i = 1; i <= n; i++) cin >> w[i];
        memset(dp, 0, sizeof(dp));
        for (int i = 1; i <= n; i++) {
   
   
            for (int j = V; j >= w[i]; j--) dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
        }
        cout << dp[V] << endl;
    }
    return 0;
}

疯狂的采药 - 多重背包

题目内容

LiYuxiang 是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。

医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同种类的草药,采每一种都需要一些时间,每一种也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是 LiYuxiang,你能完成这个任务吗?

此题和原题的不同点:

  1. 每种草药可以无限制地疯狂采摘。

  2. 药的种类眼花缭乱,采药时间好长好长啊!师傅等得菊花都谢了!

题解

思路:多重背包,和01背包做法 一模一样 相似,状态转移方程为:
d p [ j ] = d p [ j − a [ i ] ] + b [ i ] dp[j]=dp[j-a[i]]+b[i] dp[j]=dp[ja[i]]+b[i]
代码:

#include <bits/stdc++.h>
using namespace std;
long long T, m, a[10005], b[10005], dp[10000005];
int main() {
   
   
    cin >> T >> m;
    for (long long i = 1; i <= m; i++) cin >> a[i] >> b[i];
    for (long long i = 1; i <= m; i++) {
   
   
        for (long long j = a[i]; j <= T; j++) {
   
   
            dp[j] = max(dp[j], dp[j - a[i]] + b[i]);
        }
    }
    cout << dp[T] << endl;
    return 0;
}

最大连续子段和

题目内容

给定有 n n n 个整数(可能为负整数)组成的序列 a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值