题意:给出一个长度不超过1000的由小写字母组成的字符串,使用增、删、改使其变成回文串,问最少操作数。
——>>设d[i][j]为使第i位到第j位变成回文串的最少操作数,
当s[i] == s[j]时,
直接去掉两端,d[i][j] = dp(i+1, j-1);
当s[i] != s[j]时,
dp(i+1, j) + 1,dp(i, j-1) + 1同时表示增删,dp(i+1, j-1) + 1表示改;
故此时 d[i][j] = min(dp(i+1, j), dp(i, j-1), dp(i+1, j-1)) + 1;
边界条件:当i == j时,当然是0;
当j == i+1时,若s[i] == s[j],已是回文串,故为0;否则或增或删或改都只需1步,故为1;
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1000 + 10, INF = (1<<30);
int d[maxn][maxn];
char s[maxn];
int min(int a, int b, int c) //求三数最小数
{
a = (a < b) ? a : b;
a = (a < c) ? a : c;
return a;
}
int dp(int i, int j)
{
int& ans = d[i][j];
if(ans != INF) return ans;
if(j == i+1)
{
if(s[i] == s[j]) return ans = 0;
else return ans = 1;
}
if(s[i] == s[j]) //两端相等
ans = dp(i+1, j-1);
else //两端不等可增、删、改
ans = min(dp(i, j-1), dp(i+1, j), dp(i+1, j-1)) + 1;
return ans;
}
int main()
{
int T, i, j, cnt = 1;
scanf("%d", &T);
while(T--)
{
getchar();
cin>>(s+1);
int len = strlen(s+1);
for(i = 0; i < maxn; i++)
{
for(j = 0; j < maxn; j++)
d[i][j] = INF;
d[i][i] = 0;
}
dp(1, len);
printf("Case %d: %d\n", cnt++, d[1][len]);
}
return 0;
}
1次AC,感觉真爽……