UVA 10739 String to Palindrome(动态规划 回文)

String to Palindrome

题目大意:给出一个字符串s,现在可以进行3种操作(添加字母,删除字母,替换字母),将其变成回文串,求出最少的操作次数。比如abccda,可以用删除操作,删除b,d两步可变成回文;但如果用替换操作,把b换成d则只需要1步。

分析:刚开始我一直考虑它是否具有最优子结构性质,直到现在,还是不明白为什么可以用动态规划来做,大神若是看见,还望指教。

  由于添加字母和删除字母的效果是一样的,因此我们这里就只进行删除和替换操作。令dp[i][j]表示从第 i 到第 j 个字母变成回文所需要最少的操作数。

  转移方程为:当是s[i]==s[j]时,dp[i][j] = dp[i+1][j-1];此外dp[i][j] = min(dp[i+1][j],dp[i+1][j-1],dp[i][j-1]) + 1;  dp[i+1][j-1]+1 是替换操作,其他两种是删除操作。

  初始条件是:j<=i 时dp[i][j] = 0; 如果只是单一的字母,它本身就是回文

递推代码如下:

 1 # include<cstdio>
 2 # include<cstring>
 3 # include<iostream>
 4 using namespace std;
 5 char s[1005];
 6 int dp[1005][1005];
 7 int main()
 8 {
 9     int T,cas;
10     scanf("%d",&T);
11     for(cas=1; cas<=T; cas++)
12     {
13         scanf("%s",s);
14         int len =strlen(s);
15         int i,j;
16         for(i=0; i<len; i++)
17                 dp[i][i] = 0;
18         for(i=len-1; i>=0; i--)
19             for(j=i+1; j<len; j++)
20             {
21                 if(s[i]==s[j])
22                     dp[i][j] = dp[i+1][j-1];
23                 else
24                     dp[i][j] = min(min(dp[i+1][j],dp[i+1][j-1]),dp[i][j-1])+1;
25             }
26         printf("Case %d: %d
",cas,dp[0][len-1]);
27     }
28     return 0;
29 }

递归代码如下:

 1 # include<cstdio>
 2 # include<cstring>
 3 # include<iostream>
 4 using namespace std;
 5 char s[1005];
 6 int dp[1005][1005];
 7 int DP(int x,int y){
 8     if(dp[x][y] != -1)
 9         return dp[x][y];
10     if(y <= x )
11         return dp[x][y] = 0;
12     if(s[x] == s[y])
13         dp[x][y] = DP(x+1,y-1);
14     else
15         dp[x][y] = min( min(DP(x+1,y),DP(x+1,y-1)),(DP(x,y-1))) + 1;
16         return dp[x][y];
17 }
18 int main(){
19     int T,cas;
20     scanf("%d",&T);
21     for(cas=1;cas<=T;cas++){
22         scanf("%s",s);
23         int len =strlen(s);
24         memset(dp,-1,sizeof(dp));
25         printf("Case %d: %d
",cas,DP(0,len-1));
26     }
27     return 0;
28 }
原文地址:https://www.cnblogs.com/acm-bingzi/p/3217692.html