timus 1635. Mnemonics and Palindromes URAL 解题报告

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章