1. 程式人生 > >HDU 1513 Palindrome:LCS(最長公共子序列)or 記憶化搜索

HDU 1513 Palindrome:LCS(最長公共子序列)or 記憶化搜索

ble urn size rom str 個數 blog using reverse

題目鏈接: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 }

HDU 1513 Palindrome:LCS(最長公共子序列)or 記憶化搜索