Easy Problem-简单DP

  • Easy Problem
  • 思路:设dp [ i ] [ j ] 表 示 前 i 位 匹 配 了 hard 的 前 j 个 字 符,破 坏 掉 需 要 的 最 小 的 代 价 。
  • 破 毁 掉  前 1 个 只 能 破 坏 自 己,坏 掉 前 两 个 可以通过破坏第一个 或第二个 ,依次类推,按顺序转移
  • dp  [ i ] [ 3 ] 转移 是min ( d p [ i -  1 ] [ 3 ], d p [ i - 1 ] [ 2 ] ); 而dp[ i ] [ 2 ] =min ( dp [ i - 1 ] [ 1 ],dp [ i - 1 ] [ 2 ]);
  • 这样 dp[ i ][ 3 ]就是 在破坏 第一个 第二个 第三个 中 取了最小值。
  • 长度为 nnn 的字符串每个字符都有其消除花费权值,使用最小的花费消除字符使字符串中不存在hard(非必须连续)
  • 考虑动态规划,对于字符a来说转移方程为:dp[ i − 1] [ 0 ] 是把 i 位置之前(不包括 i )的字符h全部清除,
  •  dp[ i ] [ 1 ]+cost[ i ]是把 iii 位置之前(包括 i )的字符a全部清除,两者取最小值即可,其余字符rd同理。
  • #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define maxn 123456
    const ll inf=1e17;
    ll n,a[maxn],dp[maxn][5],x;
    char str[maxn];
    int main()
    {
        scanf("%lld%s",&n,str);
        for(int i=1; i<=n; i++)
        {
            scanf("%lld",&x);
            if(str[i-1]=='h')
            {
                dp[i][0]=dp[i-1][0]+x;
                dp[i][1]=min(dp[i-1][1],dp[i-1][0]);
                dp[i][2]=dp[i-1][2];
                dp[i][3]=dp[i-1][3];
            }
            else if(str[i-1]=='a')
            {
                dp[i][0]=dp[i-1][0];
                dp[i][1]=dp[i-1][1]+x;
                dp[i][2]=min(dp[i-1][1],dp[i-1][2]);
                dp[i][3]=dp[i-1][3];
            }
            else if(str[i-1]=='r')
            {
                dp[i][0]=dp[i-1][0];
                dp[i][1]=dp[i-1][1];
                dp[i][2]=dp[i-1][2]+x;
                dp[i][3]=min(dp[i-1][3],dp[i-1][2]);
            }
            else if(str[i-1]=='d')
            {
                dp[i][0]=dp[i-1][0];
                dp[i][1]=dp[i-1][1];
                dp[i][2]=dp[i-1][2];
                dp[i][3]=dp[i-1][3]+x;
            }
            else
            {
                dp[i][0]=dp[i-1][0];
                dp[i][1]=dp[i-1][1];
                dp[i][2]=dp[i-1][2];
                dp[i][3]=dp[i-1][3];
            }
        }
        printf("%lld\n",min(min(dp[n][0],dp[n][1]),min(dp[n][2],dp[n][3])));
        return 0;
    }
  • 或者记忆化:直接dp[i][j]表示放了i个数匹配hard匹配到了第j位。每次决策有两种。
    删除:代价ai,强制j保持不变。     不删除:无代价,j根据s[i]是否和j+1匹配来决定是否+1。
  • #include<bits/stdc++.h>
    using namespace std;
    #define inf 1e18
    #define maxn 123456
    #define ll long long
    ll dp[maxn][10],n,a[maxn];
    char str[maxn];
    char s[5]= {'h','a','r','d'};
    ll dfs(int id,int k)
    {
        if(id==n+1)return 0;
        if(dp[id][k]!=-1)return dp[id][k];
        dp[id][k]=inf;
        if(str[id]==s[k+1])
        {
            if(k!=2)dp[id][k]=min(dp[id][k],dfs(id+1,k+1));
        }
        else dp[id][k]=min(dp[id][k],dfs(id+1,k));
        dp[id][k]=min(dp[id][k],dfs(id+1,k)+a[id]);
        return dp[id][k];
    }
    int main()
    {
        memset(dp,-1,sizeof(dp));
        scanf("%lld%s",&n,str+1);
        for(int i=1; i<=n; i++)
            scanf("%lld",&a[i]);
        printf("%lld\n",dfs(1,-1));
        return 0;
    }
    

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值