poj 1159 Palindrome
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 53525 | Accepted: 18481 |
Description
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
Output
Sample Input
5 Ab3bd
Sample Output
2
题目意思:给你个字符串。求最少须要加入几个字符使它变成一个回文字符串;
解题思路:求给出的字符串和逆序的字符串的最长公共子序列,用总长度减去这个最长公共子序列的长度就可以;
求最长公共子序列(LCS):
字符串:s: S1S2S3S4.......Si,t: T1T2T3T4..........Tj;
定义一个数组dp[i][j]表示S1S2S3S4.......Si和T1T2T3T4..........Tj所相应的最长公共子序列。
则S1S2S3S4.......Si+1和T1T2T3T4..........Tj+1所相应的最长公共子序列可能为:
(1)假设Si+1==Tj+1,则S1S2S3S4.......Si和T1T2T3T4..........Tj所相应的最长公共子序列+1;
(2)S1S2S3S4.......Si+1和T1T2T3T4..........Tj所相应的最长公共子序列;
(3)S1S2S3S4.......Si和T1T2T3T4..........Tj+1所相应的最长公共子序列。
所以dp的状态转移方程为dp[i][j]=max( dp[i-1][j-1] + (a[i]==b[j]) , max( dp[i-1][j] , dp[i][j-1] ) )
只是这里依然存在一个问题那就是dp数组的大小。依照上面的思路我们须要定义dp[5000+1][5000+1],而这远远会超于所给定内存的大小,为此有两种解决的方法:
(1)将dp的类型定义为short;
#include <iostream> #include <string.h> using namespace std; #define MAX 5000+1 int n; char s[MAX]; short dp[MAX+1][MAX+1]; int max(int a,int b){ return a>b?a:b; } void solve(){ for (int i=0;i<n;i++){ dp[0][i]=0; dp[i][0]=0; } for (int i=0;i<n;i++) for (int j=0;j<n;j++){ if (s[i]==s[n-1-j]) dp[(i+1)][j+1]=dp[i][j]+1; else dp[(i+1)][j+1]=max(dp[i][j+1],dp[(i+1)][j]); } cout<<n-dp[n][n]<<endl; } int main(){ while (cin>>n){ for (int i=0;i<n;i++){ cin>>s[i]; } solve(); } return 0; }
(2)採用滚动数组;
由状态转移方程dp[i][j]=max( dp[i-1][j-1] + (a[i]==b[j]) , max( dp[i-1][j] , dp[i][j-1] ) )我们能够知道 i 所控制的行的值是由 i-1 和 i 所控制的行的值所确定的。因此我们仅仅须要每回记录前一个的。以便计算当前的,当计算下一个的时候,下一个的存放地址在最前面的地方,(简单说 先记录了a。然后又记录了b。再记录c的时候。把c的存放放到a上,即覆盖a),这样dp的定义就变成了dp[2][5000+1]。
#include <iostream> #include <string.h> using namespace std; #define MAX 5000+1 int n; char s[MAX]; int dp[2][MAX+1]; int max(int a,int b){ return a>b?a:b; } void solve(){ for (int i=0;i<n;i++){ dp[0][i]=0; dp[1][i]=0; } for (int i=0;i<n;i++) for (int j=0;j<n;j++){ if (s[i]==s[n-1-j]) dp[(i+1)%2][j+1]=dp[i%2][j]+1; else dp[(i+1)%2][j+1]=max(dp[i%2][j+1],dp[(i+1)%2][j]); } cout<<n-dp[n%2][n]<<endl; } int main(){ while (cin>>n){ for (int i=0;i<n;i++){ cin>>s[i]; } solve(); } return 0; }