「Luogu P1435」迴文字串 解題報告
阿新 • • 發佈:2018-12-25
題面
主要大衣大意:
給定一個字串,求至少加入多少個字元才能使字串變成迴文字串
下面就是我一本正經的胡說八道題解
思路:
很顯然,這應該是一道典型的最長公共子序列的題目
因此,主要思想就是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)