HDU 1513 Palindrome:LCS(最长公共子序列)or 记忆化搜索
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1513
题意:
给你一个字符串s,你可以在s中的任意位置添加任意字符,问你将s变成一个回文串最少需要添加字符的个数。
题解1(LCS):
很神奇的做法。
先求s和s的反串的LCS,也就是原串中已经满足回文性质的字符个数。
然后要变成回文串的话,只需要为剩下的每个落单的字符,相应地插入一个和它相同的字符即可。
所以答案是:s.size()-LCS(s,rev(s))
另外,求LCS时只会用到lcs[i-1][j-1],lcs[i-1][j],lcs[i][j-1],因为空间不够,改为滚动数组,将第一维[MAX_N]变为[2]。
题解2(记忆化搜索):
做法是对的,但是空间占用太大,会MLE。
dfs(x,y)表示让s串中[x,y]这个区间变为回文串的花费。
两种情况:
(1)s[x]==s[y]:
s[x]和s[y]已经配对,所以return dfs(x+1,y-1);
(2)s[x]!=s[y]:
有两种解决办法:
1.让[x+1,y]变为回文串,然后在y的右边添加一个字符等于s[x]。
2.让[x,y-1]变为回文串,然后在x的左边添加一个字符等于s[y]。
所以return min(dfs(x+1,y),dfs(x,y-1))+1;
判断dfs结束边界:
(1)dp[x][y]!=-1:之前已经算过了,那就不用再算一遍了,return dp[x][y]。
(2)x==y: return 0;
(3)x+1==y: 如果s[x]==s[y],return 0;如果s[x]!=s[y],return 1;
另外,每次dfs算出新的dp时,及时保存到dp数组中。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 #define MAX_N 5005 6 7 using namespace std; 8 9 int n; 10 int dp[2][MAX_N]; 11 string s; 12 13 int lcs(string a,string b) 14 { 15 memset(dp,0,sizeof(dp)); 16 for(int i=1;i<=a.size();i++) 17 { 18 for(int j=1;j<=b.size();j++) 19 { 20 if(a[i-1]==b[j-1]) dp[i&1][j]=dp[(i-1)&1][j-1]+1; 21 else dp[i&1][j]=max(dp[(i-1)&1][j],dp[i&1][j-1]); 22 } 23 } 24 return dp[a.size()&1][b.size()]; 25 } 26 27 int palindrome(string s) 28 { 29 string rev=s; 30 reverse(rev.begin(),rev.end()); 31 return s.size()-lcs(s,rev); 32 } 33 34 int main() 35 { 36 while(cin>>n>>s) 37 { 38 cout<<palindrome(s)<<endl; 39 } 40 }
没AC Code:
1 // dp[x][y] = min num of chars appended to s 2 // dp[x][x] = 0 3 // 4 // 1) s[i] != s[j]: 5 // dp[x][x+1] = 1 6 // dp[x][y] = min(dp[x+1][y], dp[x][y-1]) + 1 7 // 8 // 2) s[i] == s[j] 9 // dp[x][y] = dp[x+1][y-1] 10 11 #include <iostream> 12 #include <stdio.h> 13 #include <string.h> 14 #define MAX_N 5005 15 16 using namespace std; 17 18 int n; 19 int dp[MAX_N][MAX_N]; 20 string s; 21 22 int dfs(int x,int y) 23 { 24 if(dp[x][y]!=-1) return dp[x][y]; 25 if(x==y) return dp[x][y]=0; 26 if(x+1==y) return dp[x][y]=(s[x]==s[y]?0:1); 27 if(s[x]==s[y]) return dp[x][y]=dfs(x+1,y-1); 28 return dp[x][y]=min(dfs(x+1,y),dfs(x,y-1))+1; 29 } 30 31 int main() 32 { 33 while(cin>>n>>s) 34 { 35 memset(dp,-1,sizeof(dp)); 36 cout<<dfs(0,s.size()-1)<<endl; 37 } 38 }