首页 > 其他 > 详细

密码脱落 (区间DP)

时间:2021-06-04 22:25:06      阅读:20      评论:0      收藏:0      [点我收藏+]
  • 题目:密码脱落
  • 思路:区间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)

原文:https://www.cnblogs.com/K2MnO4/p/14850857.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!