`
wangqisen
  • 浏览: 46956 次
文章分类
社区版块
存档分类
最新评论

1159Palindrome之求最大子序列dp poj-1159-Palindrome-学习滚动数组

 
阅读更多
Palindrome
Time Limit:3000MS Memory Limit:65536K
Total Submissions:48933 Accepted:16817

Description

A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a program which, given a string, determines the minimal number of characters to be inserted into the string in order to obtain a palindrome.

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.

Input

Your program is to read from standard input. The first line contains one integer: the length of the input string N, 3 <= N <= 5000. The second line contains one string with length N. The string is formed from uppercase letters from 'A' to 'Z', lowercase letters from 'a' to 'z' and digits from '0' to '9'. Uppercase and lowercase letters are to be considered distinct.

Output

Your program is to write to standard output. The first line contains one integer, which is the desired minimal number.

Sample Input

5
Ab3bd

Sample Output

2
#include<iostream>
using namespace std;
#define NUMMAX 5001
short int getLCS(char s1[],char s2[],int len1,int len2);
short int dp[NUMMAX][NUMMAX];
int main(){
	int N;
	cin>>N;
	char s1[NUMMAX],s2[NUMMAX];
	for(int i=1;i<=N;i++){
		cin>>s1[i];
		s2[N-i+1]=s1[i];
	}
	cout<<N-getLCS(s1,s2,N,N);
	system("pause");
}
short int max(int a,int b){
	return a>b?a:b;
}
short int getLCS(char s1[],char s2[],int len1,int len2){
	for(int i=0;i<=len2;i++)
		dp[0][i]=0;
	for(int i=0;i<=len1;i++)
		dp[i][0]=0;
	for(int i=1;i<=len1;i++){
		for(int j=1;j<=len2;j++){
			if(s1[i]==s2[j]){
				dp[i][j]=max((dp[i-1][j-1]+1),dp[i][j]);
			}else{
				dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
			}
		}
	}
	return dp[len1][len2];
}
解题报告copy之:



poj-1159-Palindrome-学习滚动数组

分类:POJ340人阅读评论(0)收藏举报

题意:

给你一串字符串,让你求最少加入几个字符,才能使得这个字符串是个回文串。

做法:

设a[i]是这个字符串,b[i]是这个字符串的逆序串。

那么a[i],b[i]的最长公共子序列就是所求的字符串里拥有的最大的回文串。

然后用总串长减去最大的回文串长度即为所求。

求最长公共子序列的公式为:

dp[i][j]=max(dp[i-1] [j],dp[i][j-1])

if(a[i]==b[i])

dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);

如果直接求的话,势必要开一个5001*5001的数组,铁定MLE。

有一下两种解决方法:

1,开short int型数组

这是poj返回的结果:

2,运用动态数组。

根据dp滚动的过程我们可以知道,dp【i】【j】的值不会与dp[i-2][0.....n]的值有关系。

那么可以把dp[i][j]的值覆盖到dp[i-2][j]上。即dp[i][j]为dp[i%2][j];

poj返回的结果:

对比以上两种方法,显而易见的可以得出2的方法很节约空间,就是耗时略长。

1,short int数组

  1. #include<iostream>
  2. #include<stdio.h>
  3. #include<string.h>
  4. #definemax(a,b)(a>b?a:b)
  5. usingnamespacestd;
  6. shortintdp[5001][5001];
  7. intmain()
  8. {
  9. inta[5001];
  10. intb[5001];
  11. inti,j;
  12. intn;
  13. charstr;
  14. cin>>n;
  15. getchar();
  16. for(i=1;i<=n;i++)
  17. {
  18. scanf("%c",&str);
  19. a[i]=str;
  20. b[n-i+1]=str;
  21. }
  22. for(i=0;i<=n;i++)
  23. {
  24. dp[i][0]=0;
  25. dp[0][i]=0;
  26. }
  27. for(i=1;i<=n;i++)
  28. {
  29. for(j=1;j<=n;j++)
  30. {
  31. dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
  32. if(a[i]==b[j])
  33. {
  34. dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
  35. }
  36. }
  37. }
  38. intlen;
  39. len=dp[n][n];
  40. printf("%d\n",n-len);
  41. return0;
  42. }
2,滚动数组

  1. #include<iostream>
  2. #include<stdio.h>
  3. #include<string.h>
  4. usingnamespacestd;
  5. intmain()
  6. {
  7. inta[5001];
  8. intb[5001];
  9. intdp[10][5001];
  10. inti,j;
  11. intn;
  12. charstr;
  13. cin>>n;
  14. getchar();
  15. for(i=1;i<=n;i++)
  16. {
  17. scanf("%c",&str);
  18. a[i]=str;
  19. b[n-i+1]=str;
  20. }
  21. dp[1][0]=dp[0][0]=0;
  22. for(i=0;i<=n;i++)
  23. {
  24. dp[0][i]=0;
  25. }
  26. for(i=1;i<=n;i++)
  27. {
  28. for(j=1;j<=n;j++)
  29. {
  30. dp[i%2][j]=max(dp[i%2][j-1],dp[(i-1)%2][j]);
  31. if(a[i]==b[j])
  32. {
  33. dp[i%2][j]=max(dp[i%2][j],dp[(i-1)%2][j-1]+1);
  34. }
  35. }
  36. }
  37. intlen;
  38. len=dp[n%2][n];
  39. printf("%d\n",n-len);
  40. return0;
  41. }

题意:

给你一串字符串,让你求最少加入几个字符,才能使得这个字符串是个回文串。

做法:

设a[i]是这个字符串,b[i]是这个字符串的逆序串。

那么a[i],b[i]的最长公共子序列就是所求的字符串里拥有的最大的回文串。

然后用总串长减去最大的回文串长度即为所求。

求最长公共子序列的公式为:

dp[i][j]=max(dp[i-1] [j],dp[i][j-1])

if(a[i]==b[i])

dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);

如果直接求的话,势必要开一个5001*5001的数组,铁定MLE。

有一下两种解决方法:

1,开short int型数组

这是poj返回的结果:

2,运用动态数组。

根据dp滚动的过程我们可以知道,dp【i】【j】的值不会与dp[i-2][0.....n]的值有关系。

那么可以把dp[i][j]的值覆盖到dp[i-2][j]上。即dp[i][j]为dp[i%2][j];

poj返回的结果:

对比以上两种方法,显而易见的可以得出2的方法很节约空间,就是耗时略长。

1,short int数组

  1. #include<iostream>
  2. #include<stdio.h>
  3. #include<string.h>
  4. #definemax(a,b)(a>b?a:b)
  5. usingnamespacestd;
  6. shortintdp[5001][5001];
  7. intmain()
  8. {
  9. inta[5001];
  10. intb[5001];
  11. inti,j;
  12. intn;
  13. charstr;
  14. cin>>n;
  15. getchar();
  16. for(i=1;i<=n;i++)
  17. {
  18. scanf("%c",&str);
  19. a[i]=str;
  20. b[n-i+1]=str;
  21. }
  22. for(i=0;i<=n;i++)
  23. {
  24. dp[i][0]=0;
  25. dp[0][i]=0;
  26. }
  27. for(i=1;i<=n;i++)
  28. {
  29. for(j=1;j<=n;j++)
  30. {
  31. dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
  32. if(a[i]==b[j])
  33. {
  34. dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
  35. }
  36. }
  37. }
  38. intlen;
  39. len=dp[n][n];
  40. printf("%d\n",n-len);
  41. return0;
  42. }
2,滚动数组

  1. #include<iostream>
  2. #include<stdio.h>
  3. #include<string.h>
  4. usingnamespacestd;
  5. intmain()
  6. {
  7. inta[5001];
  8. intb[5001];
  9. intdp[10][5001];
  10. inti,j;
  11. intn;
  12. charstr;
  13. cin>>n;
  14. getchar();
  15. for(i=1;i<=n;i++)
  16. {
  17. scanf("%c",&str);
  18. a[i]=str;
  19. b[n-i+1]=str;
  20. }
  21. dp[1][0]=dp[0][0]=0;
  22. for(i=0;i<=n;i++)
  23. {
  24. dp[0][i]=0;
  25. }
  26. for(i=1;i<=n;i++)
  27. {
  28. for(j=1;j<=n;j++)
  29. {
  30. dp[i%2][j]=max(dp[i%2][j-1],dp[(i-1)%2][j]);
  31. if(a[i]==b[j])
  32. {
  33. dp[i%2][j]=max(dp[i%2][j],dp[(i-1)%2][j-1]+1);
  34. }
  35. }
  36. }
  37. intlen;
  38. len=dp[n%2][n];
  39. printf("%d\n",n-len);
  40. return0;
  41. }
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics