密码脱落 (区间DP)
Posted K2MnO4
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了密码脱落 (区间DP)相关的知识,希望对你有一定的参考价值。
- 题目:密码脱落
- 思路:区间dp,最长回文子序列变形.
- 解析:设dp[l][r]为l->r至少需要补回dp[l][r]个字符后该子序列才能形成一个回文串.
- str[l] = str[r]:dp[l][r] = dp[l+1][r-1];
- str[l] != str[l]:dp[l][r] = min(dp[l+1][r] + 1, dp[l][r-1] + 1);
- 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)的主要内容,如果未能解决你的问题,请参考以下文章