回文串问题两题

来源:互联网 发布:淘宝app图标双11 编辑:程序博客网 时间:2024/06/03 20:41

51nod 1092

这道题其实不难,递归式子很容易想到,不过就是初始化可能缺少一些想法。。。把dp数组除0以外的位置都置为无穷大,然后一步步递归。这里需要注意到的是为了避免下标出现负数,这里我们的字符串数组从1开始输入。然后还要注意到的是,判断回文数用栈实现实在是太蠢了,直接两边往中间走就行了。递归式子:当j到i是回文序列时,dp[i]=min(dp[i],dp[j-1]+1) dp[i]表示以第i个字符为结尾的字符串的划分出来的最小子回文序列的个数.

#include<cstdio>#include<cstring>#include<string>#include<iostream>#include<algorithm>#include<stack>#define inf 0x3f3f3f3fusing namespace std;const int maxn=1e4+5;int dp[maxn];char s[maxn];/*bool judge(int i,int j){stack<int> st;string s3=s+1;string s2=s3.substr(i-1,j-i+1);//cout<<s2<<endl;int k;for(k=0;k<s2.length();k++)    st.push(s2[k]);for(k=0;k<s2.length();k++){    if(st.top()!=s2[k])    break;    st.pop();}if(k==s2.length())    return true;else    return false;}*/// tlebool judge(int i,int j){    while(i!=j&&i<j){        if(s[i]==s[j])            i++,j--;        else            return false;    }    return true;}int main(){    while(scanf("%s",s+1)!=EOF){///从位置1开始输入        memset(dp,inf,sizeof(dp));        dp[0]=0;///初始化0位置为0        int length=strlen(s+1);///计算的是从下标1开始的字符串长度        for(int i=1;i<=length;i++)          for(int j=1;j<=i;j++){            if(judge(j,i))            dp[i]=min(dp[i],dp[j-1]+1);///递归式子         }         printf("%d\n",dp[length]);    }    return 0;}

51nod  1092

这是一道用到最长公共子序列的题目,思路很容易想到,就是把原序列反转,然后求二者的最长公共子列,然后用字符串长度减去最长公共子序列的长度即可。不过在这里复习一下最长公共子序列。

如果两个序列的最后一位相同,则a[i][j]=a[i-1][j-1]+1(a代表长度分别为i,j的两个序列的最长公共子序列的长度)

如果不想等则a[i][j]=max(a[i-1][j],a[i][j])注意的是开始要先把a[0][j]和a[i][0]初始化为0

开始先用递归写了,然后发现TLE原来递归这么可怕,看来以后DP尽量用数组吧.

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>using namespace std;const int maxn=1e3+5;string s1,s2;int t,a[maxn][maxn];/*int dp(string s1,string s2){    string s3,s4;    if(!s1.size()||!s2.size())        return 0;    int l1=s1.length()-1;    int l2=s2.length()-1;    if(s1[l1]==s2[l2]){        s3=s1.substr(0,l1);        s4=s2.substr(0,l2);        return dp(s3,s4)+1;    }    else{        s3=s1.substr(0,l1);        s4=s2.substr(0,l2);        return max(dp(s1,s4),dp(s3,s2));///max先算后一项    }}*//*int dp(int l1,int l2){    if(l1==0||l2==0)        {cout<<1<<endl;return 0;}    if(s1[l1-1]==s2[l2-1])        {cout<<2<<endl;return dp(l1-1,l2-1)+1;}    else        {cout<<3<<endl;return max(dp(l1-1,l2),dp(l1,l2-1));}}*/void dp(int l){    memset(a,0,sizeof(a));    for(int i=0;i<=l;i++){       a[i][0]=0;       a[0][i]=0;    }    for(int i=1;i<=l;i++)        for(int j=1;j<=l;j++){        if(s1[i-1]==s2[j-1])            a[i][j]=a[i-1][j-1]+1;        else            a[i][j]=max(a[i-1][j],a[i][j-1]);    }}int main(){    while(cin>>s1){        int l=s1.length();        s2=s1;        reverse(s1.begin(),s1.end());        dp(l);        printf("%d\n",l-a[l][l]);    }    return 0;}