URAL1635——DP+回溯——Mnemonics and Palindromes

Description

The student Vasechkin was terribly unlucky at his oral examination. Of 42 examination questions, he didn't prepare only the last one, and he was asked exactly that question. Vasechkin was sitting in front of the professor and couldn't say anything. But the professor was in good mood and gave Vasechkin one last chance to pass the exam. He asked the poor student to name the subject in which the exam was being held. Unfortunately, Vasechkin couldn't recall the name, though he remembered that in that name there were such words as safety, programs, devices, and, possibly, informatics…
To get ready for the reexamination, Vasechkin decided to learn the name of the subject. To better remember that long string, he decided to decompose it into palindromes and learn each of the palindromes separately. Of course, the number of palindromes in the decomposition had to be as small as possible.

Input

In the first line there is the name of the subject in which Vasechkin was examined. This is a nonempty line consisting of lowercase English letters. The length of the line is at most 4000 symbols.

Output

In the first line output the minimal number of palindromes to which the name of the subject can be decomposed. In the second line output palindromes from the optimal decomposition separated by a space. If several answers are possible, output any of them.

Sample Input

input output
pasoib

6

p a s o i b

zzzqxx

3

zzz q xx

wasitacatisaw

1

wasitacatisaw

 大意:找到最小的回文子串个数并输出,学到了回溯方法,因为状态转移,最后这个点更新的就是最优的情况,所以在状态转移这里设立一个path来记录当前这个状态要转移去的下标,然后只要递推就行,自己写的O(n^3)超时了  orz。不过思路很清楚
两种方法..自己调了一下午。。。以为成功了,结果交了两发TLE+MLE两个错误0.0瞬间就惊呆了orz
自己的
#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

char  a[4200];

int dp[4200];

int b[4200][4200];

int path[4200];

int n;

char pri[4200][4200];

void inti(){

    for(int i = 1 ; i <= n; i++){

        for(int j = i + 1 ;j <= n; j++){

            int k,p;

            for( k = i,p = j; k < p; k++,p--){

                if(a[k] != a[p] )

                        break;

            }

            if(k >= p)

            b[i][j] = j - i + 1;

        }

    }

    for(int i = 1 ; i <= n; i++)

        b[i][i] = 1;



}

int main()

{

    while(~scanf("%s",a+1)){

        memset(b,0,sizeof(b));

        memset(dp,0,sizeof(dp));

        memset(path,0,sizeof(path));

     n = strlen(a+1);

    inti();

    dp[1] = 1;

    for(int i = 2 ; i <= n;i++)

        dp[i] = dp[i-1]+1;

    dp[0] = 0;

    for(int i = 1; i <= n; i++){

        for(int j = i ; j <= n; j++){

            if(dp[j-b[i][j]]+1 <= dp[j]){

                dp[j] = dp[j-b[i][j]] + 1;

                path[j] = j - b[i][j];

            }

        }

    }

    //for(int i = 1; i <= n ;i++)

    //printf("%d\n",path[i]);

     // for(int i = 1; i <= n; i++)

     //   for(int j = i+1 ; j <= n;j++)

     //       printf("%d ",b[i][j]);

     //  for(int i = 1 ; i <= n; i++)

     //      printf("%d ",dp[i]);

    printf("%d\n",dp[n]);

    int i = n ;

    int t1 = 1;

    int t2;

    memset(pri,0,sizeof(pri));

    while( i >= 1){  

         t2 = 1;

      for(int j = path[i]+1; j <= i ;j++){

          pri[t1][t2++] = a[j];

        // printf("%d%d%c ",t1,t2-1,pri[t1][t2-1]);

      }

    //  printf("\n");

      t1++;

      i = path[i];

    }

 //   printf("%d",t1);

   for(int i = t1 - 1; i >= 1; i--){

        for(int j = 1; pri[i][j] != '\0';j++)

           printf("%c",pri[i][j]);

       if(i!=1) printf(" ");

    }

   printf("\n");

    }

    return 0;

}

AC的

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

int dp[4010];

int pre[4010];

int ok[4010][4010];

char s[4010];

void print(int p)

{

    if(pre[p] == -1){

        for(int i = 0 ; i <= p ;i++){

            printf("%c",s[i]);

        }

    }

       else{

        print(pre[p]);

        printf(" ");

        for(int i = pre[p]+1; i <= p ;i++)

            printf("%c",s[i]);

    }

}



void solve()

{

    int len = strlen(s);

    for(int i = 0;i < len ;i++){//i表示长度

        for(int j = 0 ;i+j < len;j++){

            if(i == 0) ok[j][j+i] = 1; //因为从小到大所以是符合这个方程的   

            else if(i == 1) ok[j][j+i] = (s[j] == s[j+i]);

            else if(s[j] == s[j+i])

                ok[j][j+i] = ok[j+1][j+i-1];

        }

    }

    for(int i = 0; i < len ;i++){

        dp[i] = i + 1;

        pre[i] = i - 1;//从0到i是否回文

        if(ok[0][i]) {

            dp[i] = 1;

            pre[i] = -1;

            continue;

        }

        for(int j = i - 1; j >= 0 ; j--){

            if(ok[j+1][i]){//j表示i前面

                if(dp[i] > dp[j] + 1){

                    dp[i] = dp[j] + 1;

                    pre[i] = j;

                }

            }

        }

    }

    printf("%d\n",dp[len-1]);

    print(len-1);//dfs

    printf("\n");

}



int main()

{

    while(~scanf("%s",s)){

        memset(dp,0,sizeof(dp));

        memset(pre,0,sizeof(pre));

        memset(ok,0,sizeof(ok));

        solve();

    }

    return 0;

}

  

你可能感兴趣的:(ROM)