回文串匹配——POJ 1159

对应POJ 题目:点击打开链接

Palindrome

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 54734   Accepted: 18922

Description

A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a program which, given a string, determines the minimal number of characters to be inserted
into the string in order to obtain a palindrome.

As an example, by inserting 2 characters, the string "Ab3bd" can be transformed into a palindrome ("dAb3bAd" or "Adb3bdA"). However, inserting fewer than 2 characters does not produce a palindrome.

Input

Your program is to read from standard input. The first line contains one integer: the length of the input string N, 3 <= N <= 5000. The second line contains one string with length N. The string is formed from uppercase letters
from ‘A‘ to ‘Z‘, lowercase letters from ‘a‘ to ‘z‘ and digits from ‘0‘ to ‘9‘. Uppercase and lowercase letters are to be considered distinct.

Output

Your program is to write to standard output. The first line contains one integer, which is the desired minimal number.

Sample Input

5
Ab3bd

Sample Output

2

题意:给出长度为n的字符串,求最少添加多少个字符就能把原字符串变成回文串(添加的位置是任意的)

思路:最少添加数量 = 原串长度 - 原串跟其逆序串的最长公共子序列长度。

证明:原串跟其逆序串的最长公共子序列 = 原串的最长不连续回文串(比如 aABdCBcAm 的最长不连续回文串是ABCBA),既然最长不连续回文串知道了,那在剩下的每个字符的对称位置添加该字符,就能把原串变成回文串。而剩下的字符个数也就是题目的答案,接下来不言而喻。。。

要注意的是,求最长公共子序列时需要把空间压缩成一维。使用到一些技巧:

0    1    2    3    4    5   j ->

0   0    0    0    0    ...

1   0    a    b    ...

2   0    c    d    ...

i    0    ...

dp[i][j] 表示A串前i个字符跟B串前j个字符的最长公共子序列。转移方程为

if(A[i-1] == B[j-1]) 
dp[i][j] = dp[i-1][j-1]  + 1;

else dp[i][j] = max(dp[i][j-1], dp[i-1][j]);

通俗地讲就是如果A[i] == B[j],那dp[i][j] 就等于它左上角的值加1,否则dp[i][j] 就等于它左边跟它上面的值中较大的那个。

仔细想想我们就能把不必要的空间消耗省掉,具体看代码。。。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#define M 5010
using namespace std;
char s1[M];
char s2[M];
int dp[M];

int main()
{
	//freopen("in.txt", "r", stdin);
	int n;
	int i, j, t, tmp;
	while(~scanf("%d", &n))
	{
		memset(dp, 0, sizeof(dp));
		scanf("%s", s1);
		for(i=0; i<n; i++)
			s2[n-i-1] = s1[i];
		for(i=0; i<n; i++){
            tmp=0;
            for(j=0; j<n; j++){
                t=dp[j+1];
                if(s1[i] == s2[j]) dp[j+1] = tmp+1;
                else if(dp[j] > t) dp[j+1] = dp[j];
                tmp=t;
            }
        }
		printf("%d\n", n - dp[n]);
	}
	return 0;
}
时间: 2024-10-17 02:23:55

回文串匹配——POJ 1159的相关文章

关于回文串的DP问题

问题1:插入/删除字符使得原字符串变成一个回文串且代价最小 poj 3280 Cheapest Palindrome 题意:给出一个由m中字母组成的长度为n的串,给出m种字母添加和删除花费的代价,求让给出的串变成回文串的代价. Sol: 插入和删除等价,因此只需要保留 min(插入代价,删除代价)作为调整字符串的代价 如果 s[i]==s[j],那么将区间(i,j)变为回文串的代价和将区间(i+1,j-1)变为回文串的代价相同,因为此时不需要修改 如果不同,必然要将 s[i]和s[j]改为同一字

POJ 1159 Palindrome(字符串变回文:LCS)

http://poj.org/problem?id=1159 题意: 给你一个字符串, 问你做少需要在该字符串中插入几个字符能是的它变成一个回文串. 分析: 首先把原字符串和它的逆串进行匹配, 找出最长公共子序列. 那么最长公共子序列的字符串肯定是一个回文串. 所以原串剩下的部分是不构成回文的. 我们只需要添加剩下部分的字符到对应位置, 原串自然就变成了一个回文. 所以本题的解为: n 减去 (原串与逆串的LCS长度). 令dp[i][j]==x表示串A的前i个字符与串B的前j个字符的子串的最长

POJ - 1159 Palindrome(回文变形)

d.求对字符串最少添加几个字符可变为回文串. s. 简单做法是直接对它和它的逆序串求最长公共子序列长度len.n-len即为所求.(n为原串长度) 这样做的原因如下: 要求最少添加几个字符,我们可以先从原串中找到一个最长回文串,然后对于原串中不属于这个回文串的字符,在它关于回文串中心的对称位置添加一个相同字符即可.那么需要添加的字符数量即为n-最长回文串长度. 最长回文串可以看作是原串中前面和后面字符的一种匹配(每个后面的字符在前面找到一个符合位置要求的与它相同的字符).这种的回文匹配和原串与逆

poj 1159 Palindrome -- 回文串,动态规划

Palindrome Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 59029   Accepted: 20505 Description A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to write a

POJ 1159 字符串匹配问题

题目大意: 问至少添加几个字符才能保证这个字符串是个回文串 一开始想也想不到字符串匹配上,因为是找回文串,我们可以把已给字符串逆向得到一个新的字符串,然后比较两者得到最大匹配长度,最后总长度减去最大匹配长度 就是所要求的值 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 #define

POJ 3974 回文串-Manacher

题目链接:http://poj.org/problem?id=3974 题意:求出给定字符串的最长回文串长度. 思路:裸的Manacher模板题. #include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> using namespace std; const int MAXN=10

POJ 3280 Cheapest Palindrome(区间DP求改成回文串的最小花费)

题目链接:http://poj.org/problem?id=3280 题目大意:给你一个字符串,你可以删除或者增加任意字符,对应有相应的花费,让你通过这些操作使得字符串变为回文串,求最小花费.解题思路:比较简单的区间DP,令dp[i][j]表示使[i,j]回文的最小花费.则得到状态转移方程: dp[i][j]=min(dp[i][j],min(add[str[i]-'a'],del[str[i]-'a'])+dp[i+1][j]); dp[i][j]=min(dp[i][j],min(add[

POJ 1159-Palindrome(dp_回文串+滚动数组)

Palindrome Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Description A palindrome is a symmetrical string, that is, a string read identically from left to right as well as from right to left. You are to wr

POJ 8471 切割回文 【dp】【北大ACM/ICPC竞赛训练】

1 #include<iostream> 2 #include<vector> 3 #define INF 100000 4 using namespace std; 5 6 string s; 7 char a[1005]; 8 vector<int> hui[1005];//hui[i]里的k指 k到i组成回文 9 int dp[1005];//dp[i]代表前i个字符要切几刀 10 11 int main(){ 12 int t; cin>>t; 13