Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 39691 | Accepted: 13485 |
Description
Input
Output
Sample Input
5 Ab3bd
Sample Output
2
题意:
求出将给定字符串变成回文词所需要插入的最少字符数,并输出任意给定的字符串的回文词。
分析:
首先拿一个字符串AbDCb观察,最优解为AbCDCbA。可以发现其对应关系:A b - D C b - 与 A b C D C b A。采用LCS(Longest Common Subsequence,最长公共子串-可不连续)算法求出最大重叠的部分。利用一个LenMatrix[N][N]二维数组记录下重叠长度,利用一个DirectFlag[N][N]记录下长度增长路线,利用record[LEN]记录下取得最长子串所覆盖的字符。输出完整的回文数要利用record数组从两边向中间靠拢,直到全部输出。
POJ1159只要求求出所需最少的字符数,下面的代码同时将最后生成的回文词也输出了。
程序源代码如下:
#include <iostream> using namespace std; #define LEN 100 char array[LEN]={' '},inver[LEN]={' '}; char HuiWen[LEN*2]; bool record[LEN]={0}; short LenMatrix[LEN][LEN] = {0}; char DirectFlag[LEN][LEN] = {0}; short getLCSLength(int n) { int i,j; for (i=1;i<=n;++i) { for (j=1;j<=n;++j) { if (array[i]==inver[j]) { LenMatrix[i][j] = LenMatrix[i-1][j-1] + 1; DirectFlag[i][j] = 1; } else if (LenMatrix[i-1][j] >= LenMatrix[i][j-1]) { LenMatrix[i][j] = LenMatrix[i-1][j]; DirectFlag[i][j] = 2; } else { LenMatrix[i][j] = LenMatrix[i][j-1]; DirectFlag[i][j] = 3; } } } return LenMatrix[n][n]; } void BackRecord(int i, int j) { if(!i || !j) return; switch(DirectFlag[i][j]) { case 1: BackRecord (i-1,j-1); record[i]=true; break; case 2: BackRecord (i-1,j); break; case 3: BackRecord (i,j-1); } } void showWhole(int n,int min) { int i=1; int j=n; int k=0; int half=min/2; while(1) { while(record[i]) { HuiWen[k]=array[i]; HuiWen[min-1-k]=array[i]; k++; i++; j--; } if(k>half)break; while(!record[i]) { HuiWen[k]=array[i]; HuiWen[min-1-k]=array[i]; k++; i++; } if(k>half)break; while(record[j]) { HuiWen[k]=array[j]; HuiWen[min-1-k]=array[j]; k++; i++; j--; } if(k>half)break; while(!record[j]) { HuiWen[k]=array[j]; HuiWen[min-1-k]=array[j]; k++; j--; } if(k>half)break; } HuiWen[min]='\0'; cout<<HuiWen<<endl; } int main() { freopen("in.txt","r",stdin); int n; cin>>n; cin>>array+1; int i; for(i=1;i<=n;i++)inver[i]=array[n+1-i]; //字符串倒置 inver[i]='\0'; short comLen=getLCSLength (n); //利用矩阵累加法得到最长子串 if(comLen==1) //没有公共子串 { cout<<n-1<<endl; cout<<array+1<<inver+2<<endl; return 0; }else { BackRecord(n,n); //后退,记录下最长公共子串的路线 cout<<n-comLen<<endl; showWhole(n,n+n-comLen); } return 0; }
/*
测试用例:
14
dA432b3b11234d
*/
输出结果:
注意:用例字符串的最大长度在程序中为LEN=100,若超过请手动修改。