问题描述
回文词是一种对称的字符串。任意给定一个字符串,通过插入若干字符,都可以变成回文词。此题的任务是,求出将给定字符串变成回文词所需要插入的最少字符数。
比如 “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 ",dp(1,n)); 27 return 0; 28 }