「Luogu P1435」回文字串 解题报告

题面

主要大衣大意:

给定一个字符串,求至少加入多少个字符才能使字符串变成回文字符串

下面就是我一本正经的胡说八道题解

思路:

很显然,这应该是一道典型的最长公共子序列的题目

因此,主要思想就是DP

方程式也挺好推的

于是我们就来讲一下为什么这题能用最长公共子序列(LCS)求解

证明:

求的是什么?

想要使这个字符串加入最少的字符变成一个回文串,那么肯定就是要是字符串中不能回文的部分回文

说起来比较难理解,比如:Ab3bd最少添的字符就是A对应的一个A,最后d对应的一个d

我们可以发现,最少要添的字符就是不能匹配的字符数=原字符串长度len-最长回文串的长度

这就变成了求最长回文串的题目

怎么求?

又经验的人肯定就会用最长公共子序列去解,但是一些人可能要问为什么,那么我们这里就来证明一下

由于回文串是回文的(废话),也就是说,把原来的字符串反转一遍,最长回文串的长度还是不变

于是我们就变成了求两串的公共子序列的长度——其实思想就是回文串正着和反着的效果是一样的,也就是抓住这个特性,去求公共系序列的长度

转移方程(最好自己去推一下):

if(a[i]==b[j])//目标状态是f[len][len]
    f[i][j]=f[i-1][j-1]+1;//表示i,j两位置相等,那么就由i-1,j-1的状态(最优解)+1得到
else
    f[i][j]=max(f[i-1][j],f[i][j-1]);//否则去掉i或j,转移最优解

Code:

#include<bits/stdc++.h>
#define N 1010
using namespace std;
int len;
char a[N],b[N];
int f[N][N];
int main()
{
    int i,j;
    scanf("%s",a+1);
    len=strlen(a+1);
    for(i=1;i<=len;i++)
        b[i]=a[len-i+1];//反转
    for(i=1;i<=len;i++)
        for(j=1;j<=len;j++)
            if(a[i]==b[j])
                f[i][j]=f[i-1][j-1]+1;
            else
                f[i][j]=max(f[i-1][j],f[i][j-1]);
    printf("%d",len-f[len][len]);//长度减去最长回文串长度
    return 0;
}

拓展知识:

最长上升子序列(LIS)

推荐题目(进阶,就是比较难的意思):

【模板】最长公共子序列

猜你喜欢

转载自www.cnblogs.com/hovny/p/10171998.html