Uva - 10739 - String to Palindrome

题意:给出一个长度不超过1000的由小写字母组成的字符串,使用增、删、改使其变成回文串,问最少操作数。

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=114&problem=1680

——>>设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,感觉真爽…… 

你可能感兴趣的:(Uva - 10739 - String to Palindrome)