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;
}