[蓝桥杯][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;
}