timus 1635. Mnemonics and Palindromes URAL 解题报告
题目大意,面试为了记住更多的单词,貌似,就想将一行字符串(由26个小写字母写组成的),分成几个回文串的形式!
输出个数和回文串!
例如:
pasoib | 6 p a s o i b |
zzzqxx | 3 zzz q xx |
wasitacatisaw | 1 wasitacatisaw |
这个题貌似不难是很简单的DP,但是当时当时有一个细节没想好,导致错了N遍了…… 难度才200+啊,当时我用一位数组dp[i]表示前i个字符最少能构成多少个回文串啊,状态转移是dp[i]=dp[j] j<i 并且j--i是回文串,当时想既然j--i是一个回文串了,那么个数就等于dp[j],不用再增加了,后来看了dicuss里面的讨论才知道自己错在哪里了……
0--j可能是一个回文串,j--i可能是一个回文串,但是dp[i]!=dp[j] ,只能说明j-i是一个,应该是dp[j-1]+1 才对啊……
改完这里之后又发现超时,原因是我的算法是O(n^3)的算法,每次判断是不是回文串就是一个O(n)的算法,后来与处理了一下,枚举中点,并且将这个也看做时中点的左侧点…… 预处理接近O(n^2) 但是没超时,我很郁闷,后来才知道,预处理虽然比简单的判断回文串的函数复杂,但是只调用了一次而已,而简单的判断回文串的On的算法是嵌套在里面的,而现在这个是并列的,是两个O(n^2) 算法……
一个破题调试一天了,郁闷,得长记性了……
找不到问题的时候应该仔细研究下代码并且尝试自己出出测试数据……
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
using namespace std;
#define mem(a,v) memset(a,v,sizeof(a))
#define N 4004
char ch[N];
int dp[N];
bool f[N][N];
short father[N];
void init()
{///预处理,虽然效率不是很高,但毕竟只调用一次啊
memset(f,-1,sizeof(f));
int len=strlen(ch);
int x,y;
f[0][0]=1;
f[len-1][len-1]=1;
for(int i=0;i<len-1;++i)
{///枚举中点,这里的中点也有可能是中相邻的点;就是说1221这个回文串没有中点,2只能是中点相邻点点
f[i][i]=1;
x=y=i;
while(x>=0&&y<len)
{
if(ch[x]!=ch[y])
{
while(x>=0&&y<len)
{
f[x--][y++]=0;
}
}else f[x--][y++]=1;
}
x=i;y=i+1;
while(x>=0&&y<len)
{
if(ch[x]!=ch[y])
{
while(x>=0&&y<len)
{
f[x--][y++]=0;
}
}else f[x--][y++]=1;
}
}
}
bool slove(int x,int y)
{///判断x--y串中
bool flag=true;
while(true)
{
if(ch[x++]!=ch[y--]){flag=false;break;}
if(x>y)break;
}
return flag;
}
int main()
{
mem(dp,0x3f3f);
scanf("%s",&ch);
init();
int len=strlen(ch);
dp[0]=1;
for(int i=0;i<len;++i)
{
dp[i]=i+1;
father[i]=i;
}
//cout<<dp[3]<<endl;
for(int i=1;i<len;++i)
{
for(int j=0;j<i;++j)
{///寻找回文串
if(f[j][i])
{
if(j==0){ dp[i]=1; father[i]=0;}
else if(dp[i]>dp[j-1]+1){ dp[i]=dp[j-1]+1; father[i]=j;}///这里坑死人了
// if(f(j,i)) cout<<dp[i]<<"==="<<j<<" ====!!!!!!!============ "<<i<<endl;
}
}if(dp[i]>dp[i-1]+1){ dp[i]=dp[i-1]+1 ;father[i]=i; }
}
//cout<<"father"<<father[len-1]<<endl;
stack<char> sta;
int cnt=0;
for(int i=len-1;i>=0;--i)
{
int len0=father[i];
for(int k=i;k>=len0;k--)
{
sta.push(ch[k]); i=k;
}cnt++;
if(i!=0)sta.push(' ');
}
//if(cnt!=dp[len-1])while(true){};
cout<<cnt<<endl;
while(!sta.empty())
{
cout<<sta.top(); sta.pop();
}
return 0;
}