POJ-1159 回文串 【LSC DP or +滚动数组省空间】
题目链接:http://poj.org/problem?id=1159
题意:求n个字符的字符串中插入 最少的字符 使得其为回文串
题解:最少的字符数 = len(长度) - LSC (原串和逆串的最长公共子串),即求LSC
法一:
if(当前 si == tj ) dp[i+1][j+1] = 1 + dp[i][j];
else dp[i+1][j+1] = max(dp[1+i][j] , dp[i][j+1]);
内存超限,dp[][]爆掉了看大神的题解改成short过了
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
#include <cmath>
using namespace std;
#define me(a) memset(a,0,sizeof(a))
const int maxn = 5002;
int n;
short dp[maxn][maxn]; //int 爆内存
int main(){
char s[maxn],t[maxn];
while(~scanf("%d",&n)){
me(dp);
scanf("%s",s+1);
int len = strlen(s+1);
if(len==0){
printf("0\n");
continue;
}
for(int i=1,j=len;i<=len;i++,j--){//反转
t[i] = s[j];
}
//LSC 最长公共子串
for(int i=1;i<=len;i++){
for(int j=1;j<=len;j++){
if(s[i] == t[j]){//上左方 +1
dp[i+1][j+1] = 1 + dp[i][j];
}else{// 继承 max(上方,左方)
dp[i+1][j+1] = max(dp[1+i][j] , dp[i][j+1]);
}
}
}
printf("%d\n",n-dp[len+1][len+1]);
}
return 0;
}
法二:滚动数组去掉用过的空间
把我上面的DP打印出来如图:
//1表示当前位置,0表示当前状态的上方位置,规律为:
if(当前 si == tj ) dp[1][j+1] = 1 + dp[0][j];
else dp[1][j+1] = max(dp[1][j] , dp[0][j+1]);
注意:每次i后 都要更新 dp[0][j]
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
#include <cmath>
using namespace std;
#define me(a) memset(a,0,sizeof(a))
const int maxn = 5002;
int n;
int dp[5][maxn];
int main(){
char s[maxn],t[maxn];
while(~scanf("%d",&n)){
me(dp);
scanf("%s",s+1);
int len = strlen(s+1);
if(len==0){
printf("0\n");
continue;
}
for(int i=1,j=len;i<=len;i++,j--){//反转
t[i] = s[j];
}
//最长公共子串
for(int i=1; i<=len; i++){//1表示当前位置,0表示上方
for(int j=1; j<=len; j++){
if(s[i] == t[j]){
dp[1][j+1] = 1 + dp[0][j];
}else{
dp[1][j+1] = max(dp[1][j] , dp[0][j+1]);
}
}
for(int j=1;j<=len+1;j++)
dp[0][j] = dp[1][j];
}
printf("%d\n",n - dp[1][len+1]);
}
return 0;
}