hdu 1513 Palindrome 回文 LCS 滚动数组
求最少补多少个字符使所给字符串变成回文,直接dp,dp[i][j]代表从i到j的字串中最少补的字符。1、如果a[i]==a[j],dp[i][j]=dp[i+1][j-1],不用加新字符的情况;2、如果a[i]!=a[j],dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1,在中间字符串的基础上再补一个字符;n的范围是5000二维会超内存,这里注意每次dp[i][j]的更新都用到dp[i+1]和dp[i][j-1],j-1可以让j为升序,dp[i+1]用滚动数组存,因为每次只用到两层dp(和下标的奇偶性),让i降序,即可使每次计算dp[i][j]时,dp[i+1]和dp[i][j-1]均为已知,dp[2][5000]实现dp过程。
Palindrome
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2084 Accepted Submission(s): 725
Problem 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
[cpp]
#include<stdio.h>
#include<string.h>
#define size 5010
int n,dp[2][size];
char a[size];
int min(int a,int b)
{
return a>b?b:a;
}
int main()
{
int i,j,k,l,m;
while(scanf("%d",&n)!=EOF)
{
memset(a,0,sizeof(a));
memset(dp,0,sizeof(dp));
getchar();
scanf("%s",&a);
for(i=n-2;i>=0;i--)
{
for(j=i+1;j<n;j++)
{
if(a[i]==a[j])
dp[i%2][j]=dp[(i+1)%2][j-1];
else
dp[i%2][j]=min(dp[(i+1)%2][j],dp[i%2][j-1])+1;
}
}
printf("%d\n",dp[0][n-1]);
}
return 0;
}
贴一个网上的例子
滚动数组很适合用在二维DP而且是数组在很大时,可以节省内存,消除超内存的隐患!具体思想还是看了网上的资料,转载一个,共同享用吧!
滚动数组 举个简单的例子:
int i,d[100];
d[0]=1;d[1]=1;
for(i=2;i<100;i++)
d[i]=d[i-1]+d[i-2];
printf("%d",d[99]);
上面这个循环d[i]只需要解集中的前2个解d[i-1]和d[i-2];
为了节约空间用滚动数组的方法
int d[3];
d[0]=1;d[1]=1;
for(i=2;i<100;i++)
d[i%3]=d[(i-1)%3]+d[(i-2)%3];
printf("%d",d[99%3]);
注意上面的运算,我们只留了最近的3个解,数组好象在“滚动?一样,所以叫滚动数组
对于二维数组也可以用这种方法 例如:
int i,j,d[100][100];
for(i=1;i<100;i++)
for(j=0;j<100;j++)
d[i][j]=d[i-1][j]+d[i][j-1];
上?的d[i][j]忪便赖于d[i-1][j],d[i][j-1];
迿用滚动数组
int i,,j,d[2][100];
for(i=1;i<100;i++)
for(j=0;j<100;j++)
d[i%2][j]=d[(i-1)%2][j]+d[i%2][j-1];
滚动数组实际是一种节约空间的办法,时间上没什么优势,多用于DP中,举个例子先:
一个DP,平常如果需要1000×1000的空间,其实根据DP的特点,能以2×1000的空间解决问题,并且通过滚动,获得和1000×1000一样的效果。
补充:软件开发 , C++ ,