题目链接:http://poj.org/problem?id=1159
思路1:
区间DP思想:
定义dp[i][j]表示从区间(i,j)之间需要增加的字符的最少数量,那么如果s[i]==s[j],那么dp[i][j]=dp[i-1][j-1]
否则dp[i][j]=min(dp[i+1][j]+1,dp[i][j-1]+1);
如果直接DP,需要开5001*5001的数组,用int会超内存
用short int 能过;
代码如下:
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<string> 6 using namespace std; 7 short int dp[5001][5001]; 8 string s; 9 int main() 10 { 11 int n; 12 while(scanf("%d",&n)!=EOF) 13 { 14 memset(dp,0,sizeof(dp)); 15 cin>>s; 16 for(int j=0;j<n;j++) 17 for(int i=j-1;i>=0;i--) 18 if(s[i]==s[j]) 19 { 20 dp[i][j]=dp[i+1][j-1]; 21 } 22 else 23 { 24 dp[i][j]=min(dp[i][j-1]+1,dp[i+1][j]+1); 25 } 26 cout<<dp[0][n-1]<<endl; 27 } 28 return 0; 29 }
但是定义short int 不是常规的做法;
常规思路:LCS+滚动数组
思路:
很容易想到需要增加的字符长度等于字符串s的长度-字符串s与它的逆串s'的最长公共字串的长度
然后问题就转化为LCS问题,简单吧
只要在处理时用滚动数组将空间消耗从n*n降为n
至于滚动数组,我们很容易知道dp[i]与dp[i-2]无关,所以只要开个2*n的空间即可,具体见代码:
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 int dp[2][5010]; 7 char s1[5010]; 8 char s2[5010]; 9 int main() 10 { 11 int n; 12 while(scanf("%d",&n)!=EOF) 13 { 14 memset(dp,0,sizeof(dp)); 15 cin>>s1; 16 int j=0; 17 for(int i=n-1; i >= 0; i--) 18 s2[j++] = s1[i]; 19 for(int i=0;i<n;i++) 20 for(int j=0;j<n;j++) 21 if(s1[i]==s2[j]) 22 dp[(i+1)%2][j+1]=dp[i%2][j]+1; 23 else dp[(i+1)%2][j+1]=max(dp[(i+1)%2][j],dp[i%2][j+1]); 24 cout<<n-dp[n%2][n]<<endl; 25 26 27 } 28 return 0; 29 }