poj 1159 Palindrome LCS一维滚动数组优化

来源:互联网 发布:php网页设计培训 编辑:程序博客网 时间:2024/06/09 07:12

本题题意:给出一个长度为n的字符串,求添加最少的字符数目,使得该字符串为一个对称的字符串。

题解:
对于Ab3bd 而言,反向翻转得到bd3bA

A   b   3   b   db   d   3   b   A

求这两个字符串的最长公共子序列,对于非公共子序列的字符,则需要添加一个相同的字符使该字符串能够对称。
问题转化为求最长公共子序列问题。
由于题目空间大小有限,一种做法是将dp方程以short定义;
另外方法是进行滚动数组优化。
下文给出LCS常规思路,以及一种优化方法

原题地址 http://poj.org/problem?id=1159

最长公共子序列问题LCS:

给出两个子序列A,B, 如
A B C B D A B
B D C A B A
最长公共子序列为4: BCBA
递推公式: dp(i,j)为A,B当前长度为i,j的LCS

dp(i,j)=dp(i-1,j-1)+1  while A[i]==B[j]dp(i,j)=max(dp(i-1,j),dp(i,j-1))    while A[i]!=B[j]
1 2 2 3 i-1,j-1 i-1,j ↖+1 ↑ 1 2 3 4 i,j-1 ← i,j

可见dp(i,j)是依赖于上一行的2个值,当前行的1个值;
由于直接变成一维数组,会导致i-1,j-1被当前行替换,因此只需提前保存上一行的i-1,j-1值,便可归纳为一维滚动数组。

poj1159代码

// poj 1159#include <cstdio>#include <iostream>#include <cmath>#include <string>#include <cstring>#include <cstdlib>#include <algorithm>#include <stack>#include <map>#include <set>#include <vector>#include <queue>#define mem(a,b) memset(a,b,sizeof(a))typedef long long ll;typedef unsigned long long ull;using namespace std;const int INF = 0x3f3f3f3f;const int maxn = 5e3+10;int n;char s[maxn];char rs[maxn];int dp[maxn];int main(){    //freopen("in.txt","r",stdin);    while(~scanf("%d",&n)){        scanf("%s",s);        memset(dp,0,sizeof(dp));        for(int i=0;i<n;i++) rs[i]=s[n-1-i];        rs[n]='\0';        for(int i=0;i<n;i++){            int tmp = 0; // tmp = dp[j] pre level            for(int j=0;j<n;j++){                int dpj = tmp; // dpj is dp[i-1][j-1]                tmp = dp[j+1]; // save before change                if(s[i]==rs[j])                    dp[j+1]=dpj+1;                else                     dp[j+1]=max(dp[j],dp[j+1]);            }        }        printf("%d ",n-dp[n]);    }    return 0;}
原创粉丝点击