acwing算法提高之动态规划--状态机模型

123 篇文章 1 订阅

1 基础知识

暂无。。。

2 模板

暂无。。。

3 工程化

题目1:大盗阿福。

解题思路:状态表示多了一维,取0或者取1,表示不选择第i个物品和选择第i个物品。

C++代码如下,

#include <iostream>
#include <cstring>

using namespace std;

const int N = 100010;
int n;
int w[N];
int f[N][2];

int main() {
    int T;
    cin >> T;
    
    for (int C = 0; C < T; ++C) {
        cin >> n;
        for (int i = 1; i <= n; ++i) cin >> w[i];
        
        //状态计算
        for (int i = 1; i <= n; ++i) {
            f[i][0] = f[i][1] = 0;
        }
        
        for (int i = 1; i <= n; ++i) {
            f[i][0] = max(f[i-1][0], f[i-1][1]);
            f[i][1] = f[i-1][0] + w[i];
        }
        
        int res = 0;
        for (int i = 1; i <= n; ++i) {
            res = max(res, f[i][0]);
            res = max(res, f[i][1]);
        }
        cout << res << endl;
    }
    
    return 0;
}

题目2:股票买卖IV。

解题思路:DP,借用状态机模型构建状态的转移过程和初始化。

状态定义f[i][j][0]:前i天交易了j次,未持有股票时的最大价值。
状态定义f[i][j][1]:前i天,正在进行第j次交易(即已经买入了股票,等待卖出中),且持有股票的最大价值。

状态转移,

f[i][j][0] = max(f[i-1][j][0], f[i-1][j][1] + w[i])
f[i][j][1] = max(f[i-1][j][1], f[i-1][j-1][0] - w[i])

初始化过程如下,

f[i][j][0] = f[i][j][1] = -0x3f3f3f3f
f[i][0][0] = 0

最终答案,f[n][j][0]

C++代码如下,

#include <iostream>

using namespace std;

const int N = 100010, M = 110;
int n, m;
int w[N];
int f[N][M][2];

int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) cin >> w[i];
    
    //初始化
    for (int i = 0; i <= n; ++i) {
        for (int j = 0; j <= m; ++j) {
            f[i][j][0] = f[i][j][1] = -0x3f3f3f3f;
        }
    }
    for (int i = 0; i <= n; ++i) f[i][0][0] = 0;
    
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            f[i][j][0] = max(f[i-1][j][0], f[i-1][j][1] + w[i]);
            f[i][j][1] = max(f[i-1][j][1], f[i-1][j-1][0] - w[i]);
        }
    }
    
    int res = 0;
    for (int j = 0; j <= m; ++j) res = max(res, f[n][j][0]);
    cout << res << endl;

    return 0;    
}

题目3:买卖股票V。

解题思路:DP。

状态定义f[i][0]:从前i天中选择,且手中无货的最大价值。
状态定义f[i][1]:从前i天中选择,且处于冷冻期的最大价值。
状态定义f[i][2]:从前i天中选择,且手中有货的最大价值。

状态转移,

f[i][0] = max(f[i-1][0], f[i-1][1])
f[i][1] = f[i-1][2] + w[i]
f[i][2] = max(f[i-1][2], f[i-1][0] - w[i])

初始化为,

f[i][0] = f[i][1] = f[i][2] = -0x3f3f3f3f
f[0][0] = 0

最终答案,max(f[n][0], f[n][1])

C++代码如下,

#include <iostream>

using namespace std;

const int N = 100010;
int n;
int w[N];
int f[N][3];

int main() {
    cin >> n;
    
    for (int i = 1; i <= n; ++i) cin >> w[i];
    
    //初始化
    for (int i = 0; i <= n; ++i) {
        f[i][0] = f[i][1] = f[i][2] = -0x3f3f3f3f;
    }
    f[0][0] = 0;
    
    //状态转移
    for (int i = 1; i <= n; ++i) {
        f[i][0] = max(f[i-1][0], f[i-1][1]);
        f[i][1] = f[i-1][2] + w[i];
        f[i][2] = max(f[i-1][2], f[i-1][0] - w[i]);
    }
    
    cout << max(f[n][0], f[n][1]) << endl;
    
    return 0;
}

题目4:设计密码。

思考:暂时没有看懂做法。后续补充

C++代码如下,

#include <iostream>
#include <cstring>

using namespace std;

const int N = 55, mod = 1e9 + 7;
int n, m;
char str[N];
int f[N][N];

int main() {
    cin >> n >> str + 1;
    m = strlen(str + 1);
    
    int next[N] = {0};
    for (int i = 2, j = 0; i <= n; ++i) {
        while (j && str[i] != str[j + 1]) j = next[j];
        if (str[i] == str[j + 1]) j++;
        next[i] = j;
    }
    
    f[0][0] = 1;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            for (char k = 'a'; k <= 'z'; ++k) {
                int u = j;
                while (u && k != str[u + 1]) u = next[u];
                if (k == str[u + 1]) u++;
                if (u < m) f[i + 1][u] = (f[i + 1][u] + f[i][j]) % mod;
            }
        }
    }
    
    int res = 0;
    for (int i = 0; i < m; ++i) res = (res + f[n][i]) % mod;
    
    cout << res << endl;
    
    return 0;
}
  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YMWM_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值