求:为了使字符串左右对称,应该插入的最小字符数目。
设字符串为S1 S2 S3 … Sn. 这个字符串有n个字符,根据DP的基本思路,减少问题规模。如果S1和Sn匹配,则只关心S2 S3 …Sn-1,就这样问题规模减少了。如果S1和Sn不匹配,那就有两种办法。
方法1:加入S1’,字符串成S1S2 S3 … Sn S1’,则问题转化为S2 S3 … Sn。
方法2:加入Sn’,字符串成Sn’S1S2 S3 … Sn,则问题转化为S1 S3 … Sn-1。
显然,最终结果就是两种方法选最优。
设dp( i, j )表示Si … Sj要变成左右对称的字符串,需要插入的最少字符数目。
状态转换方程:
dp( i, j ) = dp( i+1, j-1 ) if Si == Sj
dp( i, j ) =Min( dp( i+1, j ), dp( i, j-1 ) ) + 1 if Si != Sj
编程实现:采用记忆化递归,比较简单
注意dp数组类型使用short类型,int型会超出内存限制#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
char str[5000];
short dp[5000][5000];
int solve(int begin,int end)
{
if(dp[begin][end] >= 0) return dp[begin][end];//has visited
if(begin >= end) return dp[begin][end] = 0;
if(str[begin] == str[end])
return dp[begin][end] = solve(begin+1,end-1);
else
{
short x,y;
x = solve(begin+1,end);
y = solve(begin,end-1);
return dp[begin][end] = x > y ? (y+1) : (x+1) ;
}
}
int main()
{
//freopen("poj1159.txt","r",stdin);
int n;
cin>>n;
memset(dp,-1,sizeof(dp));
for(int i=0;i<n;i++)
cin>>str[i];
cout<<solve(0,n-1)<<endl;
return 0;
}