题目大意:给定一个字符串,求最少插入几个字符让该字符串成为回文串
法一:
dp[i][j]表示使区间[i,j]成为回文串最小插入的字符数,则状态转移方程
1、if s[i]==s[len-1] 则:d[i][j]=d[i+1][j-1]
2、else d[i]=min(dp[i+1][j],dp[i][j-1])
首尾字符不同的时候,有两种决策。
1、将新字符插在首位,那么状态就变成了dp[i+1][j]了。
2、将新字符插在末尾,则状态就变成了dp[i][j-1]了 。比较两种决策哪种更优就好啦
别忘了初始化边界~memset(dp,0,sizeof dp);
题目限制的内存是6*10的7次方字节
贴代码环节~~~:
<span style="font-size:18px;">#include<iostream> #include<cstring> #include<algorithm> #include<cstdio> #define maxn 5001 using namespace std; short dp[maxn][maxn]; //本来用的int,4*25*10的6次方等于10的8次方 爆了 ,操了一下下度娘,用short~搜噶 char s[maxn]; int n; int main() { cin>>n; scanf("%s",s); memset(dp,0,sizeof(dp)); int l=strlen(s); for(int p=1;p<=l;p++){ for(int i=0;i<=l-p;i++){ int j=i+p-1; if(s[i]==s[j]) dp[i][j]=dp[i+1][j-1]; else{ dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1; } } } cout<<dp[0][l-1]<<endl; return 0; }</span>
法二
度娘告诉我说,这题可以用最长公共子序列来搞,就是将字符串逆序,求原字符串和逆序后的字符串的LCS的长度,原字符串的长度减去最长公共子序列的长度,就是所求的最小插入数求最长公共子序列的公式为:
dp[i][j]=max(dp[i-1] [j],dp[i][j-1])
if(a[i]==b[i])
dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
然后就可以用滚动数组啦,因为当前状态dp[i][j],只用到了dp[i-1][0...n]和dp[i][0....n]这两个状态,没有涉及到dp[i-2][0..n]的状态
所以i%2走起,原状态转移方程变为
dp[i%2][j]=max(dp[(i-1)%2] [j],dp[i%2][j-1])
if(a[i]==b[i])
dp[i%2][j]=max(dp[i%2][j],dp[(i-1)%2][j-1]+1);