【CPLUSOJ】【动态规划】最短回文串

题目链接
【问题描述】
如果一个字符串正过来读和倒过来读是一样的,那么这个字符串就被称作回文串。例如abcdcba,abcddbca就是回文串,而abcdabcd不是。
你要解决的问题是:对于任意一个字符串,输出将这个字符串变为回文串需要插入的最少字符个数,比如,ab3bd只需要插入2个字符就可以变为一个回文串。
【输入格式】
第一行是一个整数N
第二行是一个长度为N字符串S
【输出格式】
一行一个整数,表示将S变为回文串需要插入的最小字符个数
【输入样例 】
5
ab3bd
【输出样例】
2
【数据范围 】
对于所有数据,0〈n<=5000
【解题思路】
回文的意思就是正读和反读都一样。
那么基本思路就出来了,输入字符串之后把字符串倒过来接着求最长公共子序列的长度,剩下的就是要插入的长度。
但是有简化的做法,只需要把最长公共子序列的状态转移方程修改一下。
原来的状态转移方程如下:

if (s1[i]==s2[j]) f[i][j]=f[i-1][j-1]+1;
f[i][j]=max(f[i][j],max(f[i-1][j],f[i][j-1));

那么根据题意进行修改就可以了

i为倒循环,j为顺循环,i<=j<len
可以解释为第一重循环表示len-1到i的字符串,第二重循环表示i到len-1的部分
if (s[i]==s[j]) f[i][j]=f[i+1][j-1];//相同则不必添加字符
f[i][j]=min(f[i+1][j],f[i][j-1)+1);//不同则要+1,取最小

最后只需要
输出f[0][len-1]即可
【参考程序】(与解题思路的变量不同)

#include<iostream>
#include<cstdio>
using namespace std;
int n,f[5010][5010];
char a[5010];
int main()
{
	cin>>n;
	for (int i=1;i<=n;i++) cin>>a[i];
	for (int i=n;i>0;i--)
		for (int j=i;j<=n;j++) 
			if (a[i]==a[j]) f[i][j]=f[i+1][j-1];
			else f[i][j]=min(f[i+1][j]+1,f[i][j-1]+1);
	cout<<f[1][n];
	return 0;
}
posted @ 2018-05-08 18:59  Nanjo  阅读(360)  评论(0编辑  收藏  举报