[蓝桥杯][2016年第七届真题]密码脱落

要求最少添加几个字符,我们可以先从原串中找到一个最长回文子序列,然后对于原串中不属于这个回文子序列的字符,在它关于回文子序列中心的对称位置添加一个相同字符即可。那么需要添加的字符数量即为n-最长回文串长度。

const int N=1010;
int f[N][N];
char s[N];
int n;

int main()
{
    cin>>s;
    n=strlen(s);

    for(int i=n-1;i>=0;i--)
        for(int j=i;j<n;j++)
        {
            if(i == j) f[i][j]=1;
            else
            {
                if(s[i] == s[j])
                    f[i][j]=f[i+1][j-1]+2;
                else 
                    f[i][j]=max(f[i+1][j],f[i][j-1]);
            }
        }

    cout<<n-f[0][n-1]<<endl;
    //system("pause");
    return 0;
}

另解

状态表示:
\(f(i,j)\):区间\([i,j]\)至少添加几个字符才能构成回文串。
状态转移:

\[\begin{cases} f(i,j)=f(i+1,j-1) & s[i] = s[j] \\ f(i,j)=min(f(i,j-1),f(i+1,j))+1 & s[i] \ne s[j] \end{cases} \]

边界:
\(f(i,i)=0\)

const int N=1010;
int f[N][N];
char s[N];
int n;

int main()
{
    cin>>s;
    n=strlen(s);

    for(int i=n-1;i>=0;i--)
        for(int j=i+1;j<n;j++)
        {
            if(s[i] == s[j])
                f[i][j]=f[i+1][j-1];
            else 
                f[i][j]=min(f[i+1][j],f[i][j-1])+1;
        }
        
    cout<<f[0][n-1]<<endl;
    //system("pause");
    return 0;
}
posted @ 2021-04-11 08:52  Dazzling!  阅读(79)  评论(0编辑  收藏  举报