poj1159_回文dp
题意:给你一段字符串,让你求出在中间最少加入几个字符可以让他变成一段回文子串。
分析::假设S是一段字符串,S'是S的逆串,则只需求出S与S'的最长公共子序列即可的长度即可,最后用字符串的长度减去最长公共子序列的长度即是这道题目所求的加入的字母的长度。转化为LCS问题即可。
注意:
1.此题二维数组会超内存,65536k=1.6*10^7(int),而二维数组2.5*10^7,显然超内存。但是用short型可以过。
2.可以使用滚动数组,因为题目只要求最后结果,没有对过程深度考察,这里可以在纸上简单模拟一下DP的转移过程.确定好最少行数或者列数之后,重点就是在如何进行"滚动"以及如何用表达式控制这个滚动.
由于应用了滚动数组,那么空间开销就能够从5001*5001压缩到 2*5001
代码:
使用short
View Code
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 //49156K 735MS 6 //dp 7 const int maxnum=5002; 8 char s1[maxnum],s2[maxnum]; 9 short dp[maxnum][maxnum]; 10 11 int main() 12 { 13 int n,i,j; 14 scanf("%d",&n); 15 scanf("%s",s1); 16 strcpy(s2,s1); 17 int len=strlen(s1); 18 for(i=0;i<len/2;i++) 19 { 20 char ch; 21 ch=s2[i]; 22 s2[i]=s2[len-1-i]; 23 s2[len-1-i]=ch; 24 } 25 for(i=0;i<=len;i++) 26 { 27 dp[i][0]=0; 28 dp[0][i]=0; 29 } 30 for(i=1;i<=len;i++) 31 for(j=1;j<=len;j++) 32 { 33 if(s1[i-1]==s2[j-1]) 34 dp[i][j]=dp[i-1][j-1]+1; 35 else if(dp[i-1][j]>dp[i][j-1]) 36 dp[i][j]=dp[i-1][j]; 37 else 38 dp[i][j]=dp[i][j-1]; 39 } 40 printf("%hd\n",len-dp[len][len]); 41 return 0; 42 }
使用滚动数组
View Code
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 using namespace std; 5 //196K 766MS 6 //dp 滚动数组 7 const int maxnum=5002; 8 char s1[maxnum],s2[maxnum]; 9 int dp[2][maxnum]; 10 11 int main() 12 { 13 int n,i,j,t; 14 scanf("%d",&n); 15 scanf("%s",s1); 16 strcpy(s2,s1); 17 int len=strlen(s1); 18 for(i=0;i<len/2;i++) 19 { 20 char ch; 21 ch=s2[i]; 22 s2[i]=s2[len-1-i]; 23 s2[len-1-i]=ch; 24 } 25 26 //初始化 27 dp[0][0]=0; 28 dp[1][0]=0; 29 for(i=0;i<=len;i++) 30 dp[0][i]=0; 31 32 for(i=1;i<=len;i++) 33 for(j=1;j<=len;j++) 34 { 35 if(s1[i-1]==s2[j-1]) 36 dp[i%2][j]=dp[(i-1)%2][j-1]+1; 37 else if(dp[(i-1)%2][j]>dp[i%2][j-1]) 38 dp[i%2][j]=dp[(i-1)%2][j]; 39 else 40 dp[i%2][j]=dp[i%2][j-1]; 41 } 42 //printf("%d %d\n",dp[0][len],dp[1][len]); 43 t=max(dp[0][len],dp[1][len]); 44 printf("%d\n",len-t); 45 return 0; 46 }