题目的意思就是给你一个字符串,问你最少经过几次操作,能把它变成回文字符串.
操作有三种
1.在任意位置添加一个字符.
2.在任意位置删除一个字符;
3.替换掉任意一个字符;
首先我们的d[i][j]是指,将i到j之间的这个串变成回文最少要几步.
我们可以发现d[i][j]如果第i个字符,和第j个字符,是相同的.难么d[i][j] = d[i + 1][j - 1]也就是不管这两个相同的,往里面缩一位.
但是如果第i位和第j位不相同,那么我们就要比较了.
如果这两位不相同,我们有两种办法,
1.把左边那位删了,或者把右边那位删了(因为通过加上两位让他们边回文,开销肯定大,所以我们直接不考虑加.)axxxb ->xxxb
2.把左边那位变成右边那位,或者把右边那位,变成左边那位 axxxb ->bxxxb;
上面两种办法开销都是1次 ,我们我们比较 min ( d[i + 1][ j ] , d[ i ] [ j - 1] , d[ i + 1 ][ j - 1] ) + 1;
最后如果 j - i < 1了,就返回0 ,因为只有1位了肯定是回文了呀,不需要操作...
AC代码:
#include<stdio.h>
#include<string.h>
const int N = 1005;
const int INF = 0x3f3f3f3f;
char str[N];
int d[N][N];
int dp(int l , int r) {
int m;
if(d[l][r] != -1)
return d[l][r];
if(r - l < 1) {
d[l][r] = 0;
return 0 ;
}
else if(str[l] == str[r]) {
m = dp(l + 1 , r - 1);
}
else {
m = INF;
int a = dp(l + 1 , r) + 1;
if(a < m)
m = a;
int b = dp(l , r - 1) + 1;
if(b < m)
m = b;
int c = dp(l + 1 ,r - 1) + 1;
if(c < m)
m = c;
}
d[l][r] = m;
return m;
}
int main () {
int t;
int cas = 1;
scanf("%d",&t);
while(t--) {
memset(d ,-1 ,sizeof(d));
scanf("%s",str);
int len1 = 0;
int len2 = strlen(str) - 1;
printf("Case %d: %d\n",cas++ ,dp(len1 , len2));
}
}