poj1159 Palindrome (dp)

两种方法:

1.序列 i~j为回文,两种策略:

         (1)若str[ i ] == str[ j ], 则只需要 i+1~j-1 为回文, 此时:dp[ i ][ j ] = dp[ i+1 ][ j-1 ]; (2)否则只需要在 str[ j ]后加 1 个字符str[ i ]并使i+1~j 为回文或者在

           str[ i ]之前加一个str[ j ]并使i~j-1 为回文,此时:dp[ i ][ j ] = MAX(dp[i+1][j]+1, dp[i][j-1]+1)。(此时空间大,必须用short)

2.求str与~str(指将str倒回来)的最长公共子序列,答案为n-最长公共子序列中的字符个数。

  dp[ i ][ j ]为str与~str的最长公共子序列中的字符数,若str[ i ]与~str[  j ]相等,dp[ i ][ j ] = dp[ i - 1][ j - 1]+1;否则,dp[ i ][ j ] = MAX(dp[i][j-1], dp[i-1][j])。

方法1:

#include <iostream>
using namespace std;

#define MIN(a, b) a<b?a:b
#define M 5002

char str[M];
short dp[M][M];

int main()
{
	int n, l, i, j;
	
	memset(dp, 0, sizeof(dp));
    scanf("%d %s", &n, str);
    for(l = 2; l <= n; l++){
		for(i = 0; i+l-1 < n; i++){
			j = i+l-1;
			if(str[i] == str[j])
				dp[i][j] = dp[i+1][j-1];
			else 
				dp[i][j] = MIN(dp[i][j-1]+1, dp[i+1][j]+1);
		}
	}
	printf("%d\n", dp[0][n-1]);
	
	return 0;
}


方法2:滚动数组

#include <iostream>
using namespace std;

#define MAX(a, b) a>b?a:b
#define M 5005

int a[M], b[M], *tmp, *p = a, *q = b; //滚动数组,有状态转移方程知,第i行的值只与第i-1行的值有关,所以只需存储两行,形成滚动数组
char str[M];

int main()
{
   int n, i, j, k;

   scanf("%d\n%s", &n, str+1);
   memset(p, 0, sizeof(p));
   for(i = 1; i <= n; i++){
	   for(j = 1; j <= n; j++){
	       k = n-j+1;
		   if(str[i] == str[k])
		       q[j] = p[j-1]+1;
		   else
			   q[j] = MAX(q[j-1], p[j]);
	   }
	   tmp = q; q = p; p = tmp;
   }
   printf("%d\n", n-p[n]);
   return 0;
}


 

你可能感兴趣的:(poj1159 Palindrome (dp))