编程语言
首页 > 编程语言> > 算法提高课 第一章 动态规划③ (状态机模型)

算法提高课 第一章 动态规划③ (状态机模型)

作者:互联网

状态机的特点:描述的是过程,而不是结果。将一个点扩展成一个过程

1049. 大盗阿福

DP考虑方式:
image
用状态机思想考虑:
image
image

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10;

int f[N][2];//f[i][j]:走了i步,且当前位于不偷 or 偷(状态0 or 1)的所有方案的最大价值
int T,n;
int w[N];
int main()
{
    scanf("%d", &T);
    while(T--)
    {
        scanf("%d", &n);
        memset(f,0,sizeof f);//初始化所有方案的价值为0
        f[0][0] = 0,f[0][1] = -0x3f3f3f3f;//一个也不偷的价值为0,f[0][1]为不合法方案,赋值无穷小
        for (int i = 1; i <= n; i ++ )
        {
            scanf("%d", &w[i]);
        }
        for (int i = 1; i <= n; i ++ )
        {
            f[i][0] = max(f[i-1][0],f[i-1][1]);//0状态可由前一个物品的0态和1态转移
            f[i][1] = f[i-1][0] + w[i]; //1状态只能从前一个物品的0态转移
        }
        cout<<max(f[n][0],f[n][1])<<endl;//最后一步状态都是合法的,输出价值最大的即可
    }
    
    return 0;
}

1057. 股票买卖 IV

image

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10,K = 110,INF = 0x3f3f3f3f;

int w[N],n,k;
int f[N][K][2];//f[i][j][k]:前i个股票中,恰好完成j次交易,第i个天的状态为k(持仓:1,空仓:0)方案的最大价值

int main()
{
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i ++ )
    {
        scanf("%d", &w[i]);
    }
    memset(f,-INF,sizeof f);//求最大值,初始化为负无穷
    for (int i = 0; i <= n; i ++ )//前i个股票中,一次交易也没完成,且状态为空仓的价值为0
    {
        f[i][0][0] = 0;
    }
    for (int i = 1; i <= n; i ++ )//枚举股票
    {
        for(int j = 0;j<=k;j++)//枚举交易次数
        {
            //空仓状态可由持仓和空仓转移而来
            f[i][j][0] = f[i-1][j][0];//先继续空仓
            if(j) f[i][j][0] = max(f[i][j][0],f[i-1][j-1][1] + w[i]);//可交易时,才根据价值考虑卖出
            //注意:只有卖出时才构成一次完整的交易
            f[i][j][1] = max(f[i-1][j][0] - w[i],f[i-1][j][1]);//持仓状态可由持仓与空仓转移而来
        }
    }
    int ans = -1;
    for (int i = 0; i <= k; i ++ ) ans = max(ans,f[n][i][0]);
    //枚举交易次数,题目要求最后必须交易完成,即空仓状态
    cout<<ans<<endl;
    return 0;
}

1058. 股票买卖 V

image

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10,INF = 0x3f3f3f3f;

int f[N][3];//f[i][j]:考虑前i个股票,0为持仓,1为空仓的第一天,2为空仓的第2+天

int w[N],n;

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++ )
    {
        scanf("%d", &w[i]);
    }
    memset(f,-INF,sizeof f);
    f[0][2] = 0;//注意:入口:无货的第>=2天
    for (int i = 1; i <= n; i ++ )
    {
        f[i][1] = f[i-1][0] + w[i];//持仓只能从空仓转移来
        f[i][2] = max(f[i-1][1],f[i-1][2]);//空仓2+天可以从空仓第一天和空仓2+天转移来
        f[i][0] = max(f[i-1][0],f[i-1][2] - w[i]);//持仓可以从持仓和空仓2+天转移来
    }
    cout<<max(f[n][1],f[n][2])<<endl;//出口:无货的第一天 or 无货的第>=2天
    return 0;
}

1052. 设计密码

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

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

int Next[N];
char str[N];
int n;
int f[N][N];
int main()
{
    cin>>n>>str+1;
    int m = strlen(str+1);
    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;
}

标签:std,const,int,scanf,namespace,第一章,状态机,算法,include
来源: https://www.cnblogs.com/zjq182/p/16307482.html