栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

状态机模型

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

状态机模型

状态机dp 对dp问题认识:

其实dp问题是在一个有向无环图上递推的过程, 在dag上递推求得答案。 图论问题我们需要建图, 但是dp问题我们不需要真的把图建出来,其实 状态表示,f(i, j)表示的就是图中的一个节点, f(i, j)存的值是从起点到该点的值(最大值、最小值、方案数)。状态转移方程实际上就是描述的是当前点可以由前面的哪些点到达, 按照状态转移方程进行计算,最后根据状态表示求得答案。

简而言之: 状态机能使原来混沌的状态变的更加清晰。

关于状态机如何想出来:

  1. 当前节点的状态可以有哪些?
  2. 这些状态可以由哪些状态转移过来?

题目一: 大盗阿福

分析:

为什要引入状态机:

在背包问题中, 前面一个物品的选择是不会影响后一个物品, 即每个物品的选择都是独立的。

而在状态机模型中, 当前物品的选择是会影响后面物品能不能被选择,由于我们不知道当前物品是不是在最优解的选择中, 所以我们要分别计算出选当前物品和不选当前物品,即在状态表示时加一个维度表示物品是否被选择,最后根据题目的意思画出状态机,写出状态转移方程。

时间复杂度: O ( n ) O(n) O(n), 量级1e5, 1秒之内可以出解。

代码区:

#include
#include

using namespace std;

const int N = 1e5 + 10;

int n;
int w[N];
int f[N][2];

int main()
{
    int t;
    cin >> t;
    while(t --)
    {
        cin >> n;
        
        for(int i = 1; i <= n; i ++) cin >> w[i];
        
        memset(f, -0x3f, sizeof f);
        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][0] + w[i];
        }
        
        printf("%dn", max(f[n][0], f[n][1]));
    }
    
    return 0;
}

题目2: 股票买卖 IV

分析:

dp数组的初始化:

因为求的最大值, 所以初始化成负无穷即可。

我们要确保状态转移方程能够被算出来, 就是确保第一次 f(i - 1, k - 1, 0) 初值为0, 因为是第1次, k等于1。 **f(i , 0, 0)**初始化成0即可, 因为它第一次买入时在每一个点都可能进行。

时间复杂度: O ( n ∗ m ) O(n * m) O(n∗m) 量级1e7, 1秒之内可以出解。

代码区:

#include
#include

using namespace std;

const int N = 1e5 + 10, 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];
    
    memset(f, -0x3f, sizeof f);
    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][1] = max(f[i - 1][j][1], f[i - 1][j - 1][0] - w[i]);
            f[i][j][0] = max(f[i - 1][j][1] + w[i], f[i - 1][j][0]);
        }
    }
    
    int res = 0;
    for(int i = 0; i <= m; i ++) res = max(res, f[n][i][0]);
    cout << res << endl;
    
    return 0;
}

题目3: 设计密码

分析:

推荐看这位同学写的 题解

时间复杂度:

代码区:

#include
#include

using namespace std;

typedef long long LL;

const int N = 55, mod = 1e9 + 7;

int n;
char str[N];
int ne[N];
int f[N][N];

int main()
{
    cin >> n >> str + 1;
    int m = strlen(str + 1);
    
    for(int i = 2, j = 0; i <= m; i ++)
    {
        while(j && str[j + 1] != str[i]) j = ne[j];
        if(str[j + 1] == str[i]) j ++;
        ne[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 && str[u + 1] != k) u = ne[u];
                if(str[u + 1] == k) u ++;
                if(u < m) f[i + 1][u] = ((LL)f[i + 1][u] + f[i][j]) % mod;
            }
        }
    }
    
    
    int res = 0;
    for(int i = 0; i < m; i ++) res = ((LL)res + f[n][i]) % mod;
    cout << res << endl;
    
    return 0;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/883296.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号