lightoj 1033 Generating Palindromes

题目大意:

给出一个长度不超过100的字符串(仅含小写字母),问最少加几个字符能让它变为一个回文串。

如:

abcd 可以最少需要加入三个字符变成回文,比如变成 dcbabcd.

aaaa 本身即是回文,则不需要加入字符,加入字符数最小为0.

aab 最少加入一个字符,比如变为 baab.

最多一百组测试数据,每组测试数据字符串长度不超过100.

 

一开始想了一个贪心的思路,结果WA,转头就想到了反例,发现贪心不行。

转向DP思路,我们用dp[i][j]表示  str[i] - str[j] 这个子串需要变成回文的最少的添加的字符

嗯。。。。好像明了了一些了,然后思考转移的方程好像没有头绪呀 = =。

仔细发现每当我们扫到一个字符的时候,有这么几种情况:

1. 我们单独考虑字符 str[j] , 可能 str[i] - str[j - 1] 是一个回文串,我们将 str[j]  对称到 str[i] 的前面 ,  解就是 dp[i][j - 1] + 1.

2. 我们单独考虑字符 str[i] , 可能 str[i + 1] - str[j] 是一个回文串 ,  我们将 str[i] 对称到 str[j] 的后面 ,解就是 dp[i + 1][j] + 1.

3. 我们考虑字符 str[i] str[j] , str[i] == str[j] 情况下,只要内部回文就能回文,所以解就是 dp[i + 1][j - 1].

4. 我们考虑字符 str[i] str[j] , str[i] != str[j] 情况下,转移情况是 1 2 情况中的一种 , 或者还有一种情况,内部已经回文,那么我们就是首尾两个字符要回文,解就是 dp[i + 1][j - 1] + 2.

至此,转移情况理清了大致如下:

接下来是代码环节,从转移方程看出 i 依赖于 i + 1 情况,而 j 依赖于 j - 1情况,所以应该外层为 j 从 0 ~ n - 1 , 内层为 i 从 0 ~ j , 写出代码 。

PS:这题也是黑书上的一道DP的思考题,来源是IOI 2000年的比赛 。 想到那些初中的大神就有这样的思维, Orz.......

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

 

posted @ 2016-04-06 15:59  ACMZZ  阅读(240)  评论(0编辑  收藏  举报