题目:回文字串
网址:https://www.luogu.com.cn/problem/P1435
题目描述
任意给定一个字符串,通过插入若干字符,都可以变成回文词。此题要求出:将给定字符串变成回文词所需要插入的最少字符数。
比如 “Ab3bd”插入2个字符后可以变成回文词“dAb3bAd”或“Adb3bdA”,但是插入少于2个的字符无法变成回文词。
注:此问题区分大小写
输入格式
一个字符串(0<strlen<=1000)
输出格式
有且只有一个整数,即最少插入字符数
输入输出样例
输入
Ab3bd
输出
2
本题使用DP。
设dp[i, j]代表区间[i, j]变为回文字串所需要的最小操作数量。
分别向最左端及最右端插入一个相等的字符,有dp[i, j] = min(dp[i + 1, j] + 1, dp[i, j - 1])。
由于左右两个字符一样,则有dp[i, j] = min{dp[i, j], dp[i - 1, j - 1]}。
初始化的时候,令dp[i][i] = dp[i + 1][i] = 0(其中0 < i < n)即可(因为单个字符本身就是回文字串;而出现了两个相邻且相同的字符a[i]和a[i + 1],转移时代价为0)。
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn = 1000 + 5;
char s[maxn];
int n, dp[maxn][maxn] = {};
int main()
{
scanf("%s", (s + 1));
n = strlen(s + 1);
int i, j, len;
for(i = 1; i <= n; ++ i) dp[i][i] = 0;
for(len = 2; len <= n; ++ len)
{
for(i = 1, j = i + len - 1; j <= n; ++ i, ++ j)
{
dp[i][j] = min(dp[i + 1][j] + 1, dp[i][j - 1] + 1);
if(s[i] == s[j]) dp[i][j] = min(dp[i][j], dp[i + 1][j - 1]);
}
}
printf("%d
", dp[1][n]);
return 0;
}