1. 程式人生 > >「Luogu P1435」迴文字串 解題報告

「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)

推薦題目(進階,就是比較難的意思):

【模板】最長公共子序列