timus 1635. Mnemonics and Palindromes URAL 解题报告
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里面的讨论才知道自己错在哪里了……
#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;
}