题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1513
Palindrome
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4532 Accepted Submission(s): 1547
As an example, by inserting 2 characters, the string "Ab3bd" can be transformed into a palindrome ("dAb3bAd" or "Adb3bdA"). However, inserting fewer than 2 characters does not produce a palindrome.
题意:给出一个字符串,问要将这个字符串变成回文串要添加最少几个字符
思路:将该字符串与其反转求一次LCS,然后所求就是n减去最长公共子串的长度,但是要注意这里字符串最长有5000,dp数组二维都开5000的话就会超内存,这里就用到了滚动数组,因为在LCS的计算中,i的变化只相差1,所以可以通过对2取余来进行滚动
LCS: 求连个串s1,s2的最长公共自序列:dp[i][j] 表示扫描到第一个串的第i个位置第二个串的第j个位置的最长公共子序列。 当s1[i]==s2[j]时,dp[i][j] = d[i-1][j-1]+1;
当s1[i]!=s2[j]时,dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
空间优化: 通过上面的转移方程可以看出来dp[i][j]的状态之和上一列和当前列有关系,所以可以通过二维滚动数组的形式来储存,通过i的奇偶来控制
下面是代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N = 5005; 6 char s1[N],s2[N]; 7 int dp[2][N]; 8 int n; 9 10 void LCS() 11 { 12 int i,j; 13 memset(dp,0,sizeof(dp)); 14 for(i = 1; i<=n; i++) 15 { 16 for(j = 1; j<=n; j++) 17 { 18 int x = i%2; 19 int y = 1-x; 20 if(s1[i-1]==s2[j-1]) 21 dp[x][j] = dp[y][j-1]+1; 22 else 23 dp[x][j] = max(dp[y][j],dp[x][j-1]); 24 } 25 } 26 } 27 int main() 28 { 29 int i,j; 30 while(~scanf("%d",&n)) 31 { 32 getchar(); 33 scanf("%s",s1); 34 for(i = 0; i < n; i++) 35 s2[i] = s1[n-1-i]; 36 //s2[i] = '\0'; 37 LCS(); 38 printf("%d\n",n-dp[n%2][n]); 39 } 40 return 0; 41 }