密码脱落 (区间DP)

Posted K2MnO4

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了密码脱落 (区间DP)相关的知识,希望对你有一定的参考价值。

  • 题目:密码脱落
  • 思路:区间dp,最长回文子序列变形.
  • 解析:设dp[l][r]为l->r至少需要补回dp[l][r]个字符后该子序列才能形成一个回文串.
    1. str[l] = str[r]:dp[l][r] = dp[l+1][r-1];
    2. str[l] != str[l]:dp[l][r] = min(dp[l+1][r] + 1, dp[l][r-1] + 1);
    3. ps:若使用dp来写,可以看出转移方程是自上而下递推而来的,所以区间起始点l需要从大到小枚举,并且在第一种情况需要加一个特判,因为l + 1可能 > r - 1, 此时dp[l][r]应该为0,而用记忆化搜索来写只需在限制条件那判断一下区间是否越界即可
  • DP写法代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1005;
char str[N];
int dp[N][N];

int main()
{
    memset(dp, 0x3f, sizeof dp);
    cin >> str + 1;
    int n = strlen(str + 1);
    for(int i = 1; i <= n; i++) dp[i][i] = 0;
    for(int len = 2; len <= n; len ++)
    {
        for(int l = n - len + 1; l >= 1 ; l--)
        {
            int r = l + len - 1;
            if(str[l] == str[r])
            {
                if(l + 1 <= r - 1) dp[l][r] = dp[l+1][r-1];
                else dp[l][r] = 0;
            }
            else dp[l][r] = min(dp[l+1][r] + 1, dp[l][r-1] + 1);
//            cout << "l = " << l << " r = "  << r << " val= " << dp[l][r] << endl;
        }
    }
    cout << dp[1][n];
    return 0;
}

  • 记忆化搜索写法代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N = 1005;
char str[N];
int dp[N][N];
int dfs(int l , int r)
{
    if(l >= r) return dp[l][r] = 0;
    if(dp[l][r] != 0x3f3f3f3f) return dp[l][r];
    if(str[l] == str[r]) dp[l][r] = dfs(l + 1, r - 1);
    else dp[l][r] = min(dfs(l, r - 1) + 1, dfs(l + 1, r) + 1);
    return dp[l][r];
}
int main()
{
    memset(dp, 0x3f, sizeof dp);
    cin >> str + 1;
    int n = strlen(str + 1);
    int res = dfs(1, n);
    cout << res;
    return 0;
}

以上是关于密码脱落 (区间DP)的主要内容,如果未能解决你的问题,请参考以下文章

16年第七届蓝桥杯第九题_密码脱落_(贪心)

LQ0125 密码脱落LCS

1024. 视频拼接 dp

区间DP经典模型

2021春季每日一题week3 未完结

HDU 5115 Dire Wolf ——(区间DP)