题目大意 给出一个字符串,求至少需要插入多少个字符使原字符串变为回文串(如abcde不是回文串,而abcba是回文串);
算法 结合最长公共子序列问题,把原串(长度为n)逆序存储一下,求其与原串的最长公共字串长度k,则n-k即为所求。
注意 5000*5000的二维数组不会爆空间,但实际上完全可以滚动第一维,用滚动数组存储显然节省了相当的空间。
代码实现-非滚动版
<span style="font-size:14px;">#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
short f[5001][5001];
int main()
{
int n;
cin>>n;
scanf("\n");
char s1[n+1],s2[n+1];
for (int i=1;i<=n;i++)
scanf("%c",&s1[i]);
for (int i=1;i<=n;i++)
s2[n-i+1]=s1[i];
int ans=0;
for (int i=1;i<=n;i++) //求最长公共字串长;
for (int j=1;j<=n;j++)
{
if (s1[i]==s2[j])
f[i][j]=f[i-1][j-1]+1;
else
f[i][j]=max(f[i][j-1],f[i-1][j]); //可以看出,f[i][j]状态至于f[i-1][..]和f[i][..]有关,因此完全可以滚动第一维;
}
cout<<n-f[n][n];
return 0;
}
</span>
滚动版
<span style="font-size:14px;">#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
short f[2][5001];
int main()
{
int n;
cin>>n;
scanf("\n");
char s1[n+1],s2[n+1];
for (int i=1;i<=n;i++)
scanf("%c",&s1[i]);
for (int i=1;i<=n;i++)
s2[n-i+1]=s1[i];
int ans=0;
int pre=0,now=1;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=n;j++)
{
if (s1[i]==s2[j])
f[now][j]=f[pre][j-1]+1;
else
f[now][j]=max(f[now][j-1],f[pre][j]);
}
swap(pre,now); //枚举完j后pre与now交换,是滚动数组实现的关键;
}
cout<<n-f[pre][n];
return 0;
}
</span>