zoukankan      html  css  js  c++  java
  • 【BZOJ-1068】压缩 区间DP

    1068: [SCOI2007]压缩

    Time Limit: 1 Sec  Memory Limit: 128 MB
    Submit: 1001  Solved: 615
    [Submit][Status][Discuss]

    Description

      给一个由小写字母组成的字符串,我们可以用一种简单的方法来压缩其中的重复信息。压缩后的字符串除了小写字母外还可以(但不必)包含大写字母R与M,其中M标记重复串的开始,R重复从上一个M(如果当前位置左边没有M,则从串的开始算起)开始的解压结果(称为缓冲串)。 bcdcdcdcd可以压缩为bMcdRR,下面是解压缩的过程

     

      另一个例子是abcabcdabcabcdxyxyz可以被压缩为abcRdRMxyRz。

    Input

      输入仅一行,包含待压缩字符串,仅包含小写字母,长度为n。

    Output

      输出仅一行,即压缩后字符串的最短长度。

    Sample Input

    bcdcdcdcdxcdcdcdcd

    Sample Output

    12

    HINT

    在第一个例子中,解为aaaRa,在第二个例子中,解为bMcdRRxMcdRR。 

    【限制】 

    100%的数据满足:1<=n<=50 100%的数据满足:1<=n<=50

    Source

    Solution

    区间DP,做的太少了,以至于这道题转移设计出现一点错误,其实这道题写记搜比递推更容易理解.

    状态很好想到$f[l][r][0/1]$表示区间$[l,r]$中有M/无M的最短,这样显然答案为$min(f[1][n][0],f[1][n][1])$

    转移的时候显然是要枚举断点的, 断点为k,转移:

    $f[i][j][1]=min(f[i][j][1],min(f[i][k][0],f[i][k][1])+min(f[k+1][j][0],f[k+1][j][1])+1);$

    $f[i][j][0]=min(f[i][j][0],f[i][k][0]+j-k);$

    然后如果枚举到的区间$[l,r]$,如果这个$[l,r]$可以缩成一个,那么就缩,所以得到$f[i][j][0]=f[i][(i+j)>>1][0]+1$

    然后就可以了

    Code

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    #define MAXN 100 
    char S[MAXN];
    int len,f[MAXN][MAXN][2];
    bool check(int l,int r)
    {
        int mid=(l+r)>>1;
        if ((r-l+1)&1) return 0;
        for (int i=1; i<=mid-l+1; i++) if (S[l+i-1]!=S[mid+i]) return 0;
        return 1;
    }
    int main()
    {
        scanf("%s",S+1);
        len=strlen(S+1);
        for (int i=len; i>=1; i--)
            for (int j=i; j<=len; j++)
                {
                    f[i][j][0]=f[i][j][1]=j-i+1;
                    for (int k=i; k<j; k++)
                        f[i][j][1]=min(f[i][j][1],min(f[i][k][0],f[i][k][1])+min(f[k+1][j][0],f[k+1][j][1])+1);
                    for (int k=i; k<j; k++)
                        f[i][j][0]=min(f[i][j][0],f[i][k][0]+j-k);
                    if (check(i,j)) f[i][j][0]=f[i][(i+j)>>1][0]+1; 
                    if (j-i+1==1) f[i][j][1]=len+1;
                }
        printf("%d
    ",min(f[1][len][1],f[1][len][0]));
        return 0;
    }

    这道题搞了一会,感觉有点zz

  • 相关阅读:
    Java基础50道经典练习题(33)——杨辉三角
    Java基础50道经典练习题(32)——左移右移
    团队第二阶段冲刺04
    团队第二阶段冲刺03
    团队第二阶段冲刺02
    团队第二阶段冲刺01
    团队意见汇总
    各组意见汇总
    团队第一阶段冲刺07
    绩效评估01
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5857791.html
Copyright © 2011-2022 走看看