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