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

  

时间: 2024-12-21 07:44:21

URAL1635——DP+回溯——Mnemonics and Palindromes的相关文章

回文串+回溯法 URAL 1635 Mnemonics and Palindromes

题目传送门 1 /* 2 题意:给出一个长为n的仅由小写英文字母组成的字符串,求它的回文串划分的元素的最小个数,并按顺序输出此划分方案 3 回文串+回溯:dp[i] 表示前i+1个字符(从0开始)最少需要划分的数量,最大值是i+1,即单个回文串: 4 之前设置ok[j][j+i] 判断从j到j+i的字符是否为回文串(注意两个for的顺序,为满足ok[j][j+i] = ok[j+1][j+i-1]) 5 最后枚举找到最优划分点,用pre[i]记录前一个位置,print函数 输出空格 6 */ 7

Ural 1635 Mnemonics and Palindromes(DP)

题目地址:Ural 1635 又是输出路径的DP...连着做了好多个了.. 状态转移还是挺简单的.要先预处理出来所有的回文串,tag[i][j]为1表示字符串i--j是一个回文串,否则不是回文串.预处理时要用n^2的方法,即枚举回文串中间,可以分奇数和偶数两种分别求一次. 然后dp转移方程为,若tag[j][i]==1,dp[i]=min(dp[i],dp[j-1]+1); 对于最令人讨厌的路径输出,可以用pre来记录回文串前驱分裂点,然后根据这些分裂点来输出. 代码如下: #include <

ural Mnemonics and Palindromes (dp)

http://acm.timus.ru/problem.aspx?space=1&num=1635 给出一个字符串,将这个字符串分成尽量少的回文串. 起初没有思路,想着应该先预处理出所有的回文串,然后进行dp.但是字符串的长度是4000,O(n^3)肯定不行,其实可以转化为O(n^2),就是枚举中点而不是枚举起点和终点,又NC了吧. 然后就是线性的dp了.dp[i]表示到第i位为止最少的回文串数,那么dp[i] = min(dp[i],dp[j+1]+1),j < i 且i到j也是回文串.

URAL1224——背包DP+回溯——Gentlemen

Description Let's remember one old joke: Once a gentleman said to another gentleman:— What if we play cards?— You know, I haven't played cards for ten years…— And I haven't played for fifteen years…So, little by little, they decided to resurrect thei

DP专题&#183;四(树形dp)

1.poj 115 TELE 题意:一个树型网络上有n个结点,1~n-m为信号传送器,n-m+1~n为观众,当信号传送给观众后,观众会付费观看,每铺设一条道路需要一定费用.现在求以1为根,使得收到观众的费用-铺设道路的费用>=0的情况下,能最多给多少个观众观看? 思路:树形dp,dp[i][j]表示以i为根的子树中选择j个观众(叶子)最大的收益. ①如果当前结点为叶子结点,那么其dp[i][0]=0,dp[i][1]=val[i]. ②如果为其他结点,则dp[i][j]=max(dp[i][j]

[转] POJ字符串分类

POJ 1002 - 487-3279(基础)http://acm.pku.edu.cn/JudgeOnline/problem?id=1002题意:略解法:二叉查找数,map,快排... POJ 1200 - Crazy Search(基础)http://acm.pku.edu.cn/JudgeOnline/problem?id=1200题意:找出不相同的子串数量,字母表大小和子串长度会给定,这题很推荐hash入门者一做解法:hash(建议karp-rabin) POJ 1204 - Word

uva 11584 Partitioning by Palindromes 线性dp

// uva 11584 Partitioning by Palindromes 线性dp // // 题目意思是将一个字符串划分成尽量少的回文串 // // f[i]表示前i个字符能化成最少的回文串的数目 // // f[i] = min(f[i],f[j-1] + 1(j到i是回文串)) // // 这道题还是挺简单的,继续练 #include <algorithm> #include <bitset> #include <cassert> #include <

Codeforces Round #316 (Div. 2)E. Pig and Palindromes DP

E. Pig and Palindromes Peppa the Pig was walking and walked into the forest. What a strange coincidence! The forest has the shape of a rectangle, consisting of n rows and m columns. We enumerate the rows of the rectangle from top to bottom with numbe

Codeforces #316 E Pig and Palindromes DP

// Codeforces #316 E Pig and Palindromes // // 题目大意: // // 给你一张地图,n*m每个点是一个字母,现在从(0,0)出发, // 每次只能往右或者往下走,求走到(n-1,m-1)形成回文串的方法数. // // 解题思路: // // 动态规划.首先.如果起点和终点的字母不相同,那么肯定 // 不能形成回文串,直接输出0.对于能形成回文串.我们设状态 // d(step,i,j)表示走了step步,从第0行走到i行,第n-1行走到j行的 /