【IOI2000】【洛谷1435】回文字串

问题描述

回文词是一种对称的字符串。任意给定一个字符串,通过插入若干字符,都可以变成回文词。此题的任务是,求出将给定字符串变成回文词所需要插入的最少字符数。

比如 “Ab3bd”插入2个字符后可以变成回文词“dAb3bAd”或“Adb3bdA”,但是插入少于2个的字符无法变成回文词。

注:此问题区分大小写

输入格式

第一行一个整数n(3<=n<=5000)表示字符串的长度

第二行一个长度为n的字符串

输出格式

有且只有一个整数,即最少插入字符数

样例输入

5

Ab3bd

样例输出

2

题解

设读入的字符串为s,如果s[i]~s[j]是回文,那么s[i+1]~s[j-1]一定也是回文,满足区间动规的特点。

设f[i][j]表示s[i]~s[j]变成回文词需要插入的最少字符数,当s[i]==s[j]时,f[i][j]=f[i+1][j-1]+1,否则f[i][j]=min(f[i+1][j],f[i][j-1])+1。

我用的是记忆化搜索,当i>j时,由于是不合法的状态,我最初返回无穷大,但由于i>j的状态只可能从i==j &&s[i]==s[j]转移过来,所以i>j这个状态的值其实是i==j &&s[i]==s[j]这个状态的值,应该返回0。

 1 #include <cstring>
 2 #include <cstdio>
 3 int n,f[5005][5005];
 4 bool vis[5005][5005];
 5 char s[5005];
 6 int min(int x,int y)
 7 {
 8     return x<y?x:y;
 9 }
10 int dp(int i,int j)
11 {
12     if (i>j) return 0;
13     if (vis[i][j]) return f[i][j];
14     vis[i][j]=1;
15     if (i==j) return f[i][j]=0;
16     f[i][j]=2e9;
17     if (s[i]==s[j]) f[i][j]=dp(i+1,j-1);
18     f[i][j]=min(f[i][j],min(dp(i+1,j),dp(i,j-1))+1);
19     return f[i][j];
20 }
21 int main()
22 {
23     int i,j;
24     scanf("%d",&n);
25     scanf("%s",s+1);
26     printf("%d\n",dp(1,n));  
27     return 0;
28 }

猜你喜欢

转载自www.cnblogs.com/rabbit1103/p/9620373.html