题意很明确,给你一个字符串,可在任意位置添加字符,最少再添加几个字符,可以使这个字符串成为回文字符串。
看到这道题,很熟悉,貌似以前做过,可就是想不起来解法,还是以前做的不认真。很惭愧,不过这次的解更优化。
解题思路:老实说,我从来没想到要用动态规划做。或许对动态规划了解不深吧,练得少。如果要是明确求两个字符串的最长公共子序列,我知道要用动态规划,这个老师也讲了多遍。万万没想到这道题就是变形后求原串与其逆串的最长公共子序列,然后用串长减去最长公共子序列的长度就是要添加的最少的字符数。(如果有人提醒我,我就知道怎么办了,可是在比赛的时候全靠自己。)另外还需注意的是字符串长度最长Max为5000,如果用数组maxlen[Max][Max],那么内存会超出。所以引进滚动数组,只需要定义maxlen[2][Max]就可以把问题解决了。(这是从队友那里学来的)首先初始化e=0;在每次行循环中用到e=1-e 就OK了。(这个很好用,大大减少的内存的占用。)
代码如下:
View Code
1
#include
<
iostream
>
2 #include < cstring >
3 using namespace std;
4 #define Max 5005
5 char str1[Max],str2[Max];
6 int maxlen[ 2 ][Max];
7 int main()
8 {
9 int n,i,j;
10 while (cin >> n)
11 {
12 for (i = 1 ;i <= n;i ++ )
13 cin >> str1[i];
14 str1[n + 1 ] = ' \0 ' ;
15 for (i = 1 ;i <= n;i ++ ) // 字符串str1的逆串
16 str2[i] = str1[n - i + 1 ];
17 memset(maxlen, 0 , sizeof (maxlen)); // 初始化
18 int e = 0 ;
19 for (i = 1 ;i <= n;i ++ ) // 用动态规划求解
20 {
21 e = 1 - e; // 用滚动数组,保证内存不会超出
22 for (j = 0 ;j <= n;j ++ )
23 {
24 if (str1[i] == str2[j])
25 maxlen[e][j] = maxlen[ 1 - e][j - 1 ] + 1 ;
26 else {
27 int len1 = maxlen[e][j - 1 ];
28 int len2 = maxlen[ 1 - e][j];
29 if (len1 > len2) maxlen[e][j] = len1;
30 else maxlen[e][j] = len2;
31 }
32 }
33 }
34 cout << n - maxlen[e][n] << endl;
35 }
36 return 0 ;
37 }
2 #include < cstring >
3 using namespace std;
4 #define Max 5005
5 char str1[Max],str2[Max];
6 int maxlen[ 2 ][Max];
7 int main()
8 {
9 int n,i,j;
10 while (cin >> n)
11 {
12 for (i = 1 ;i <= n;i ++ )
13 cin >> str1[i];
14 str1[n + 1 ] = ' \0 ' ;
15 for (i = 1 ;i <= n;i ++ ) // 字符串str1的逆串
16 str2[i] = str1[n - i + 1 ];
17 memset(maxlen, 0 , sizeof (maxlen)); // 初始化
18 int e = 0 ;
19 for (i = 1 ;i <= n;i ++ ) // 用动态规划求解
20 {
21 e = 1 - e; // 用滚动数组,保证内存不会超出
22 for (j = 0 ;j <= n;j ++ )
23 {
24 if (str1[i] == str2[j])
25 maxlen[e][j] = maxlen[ 1 - e][j - 1 ] + 1 ;
26 else {
27 int len1 = maxlen[e][j - 1 ];
28 int len2 = maxlen[ 1 - e][j];
29 if (len1 > len2) maxlen[e][j] = len1;
30 else maxlen[e][j] = len2;
31 }
32 }
33 }
34 cout << n - maxlen[e][n] << endl;
35 }
36 return 0 ;
37 }