B1090 [SCOI2003]字符串折叠 区间dp

又一道区间dp,和上一篇类似,但是比他简单,这个只有两种转移方法,不是很复杂。直接判断是否为重复的串就行。

题干:

Description
折叠的定义如下: 1. 一个字符串可以看成它自身的折叠。记作S  S 2. X(S)是X(X>1)个S连接在一起的串的折叠。记作X(S)  SSSS…S(X个S)。 3. 如果A  A’, BB’,则AB  A’B’ 例如,因为3(A) = AAA, 2(B) = BB,所以3(A)C2(B)  AAACBB,而2(3(A)C)2(B)AAACAAACBB 给一个字符串,求它的最短折叠。例如AAAAAAAAAABABABCCD的最短折叠为:9(A)3(AB)CCD。
Input
仅一行,即字符串S,长度保证不超过100。
Output
仅一行,即最短的折叠长度。
Sample Input
NEERCYESYESYESNEERCYESYESYES
Sample Output
14
HINT
一个最短的折叠为:2(NEERC3(YES))
Source

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<ctime>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
#define duke(i,a,n) for(int i = a;i <= n;i++)
#define lv(i,a,n) for(int i = a;i >= n;i--)
#define clean(a) memset(a,0,sizeof(a))
const int INF = 1 << 30;
typedef long long ll;
typedef double db;
template <class T>
void read(T &x)
{
    char c;
    bool op = 0;
    while(c = getchar(), c < '0' || c > '9')
        if(c == '-') op = 1;
    x = c - '0';
    while(c = getchar(), c >= '0' && c <= '9')
        x = x * 10 + c - '0';
    if(op) x = -x;
}
template <class T>
void write(T x)
{
    if(x < 0) putchar('-'), x = -x;
    if(x >= 10) write(x / 10);
    putchar('0' + x % 10);
}
char s[1100];
int f[1100][1100],n,l;
bool get(int x1,int y1,int x2,int y2)
{
    if((y2 - x1 + 1) % (y1 - x1 + 1) != 0)
    return false;
    int len = y1 - x1 + 1;
    duke(i,x2,y2)
    {
        if(s[i] != s[i - len])
        return false;
    }
    return true;
}
int cal(int k)
{
    int cnt = 0;
    while(k)
    {
        cnt++;
        k /= 10;
    }
    return cnt;
}
int main()
{
    memset(f,0x3f,sizeof(f));
    scanf("%s",s + 1);
    n = strlen(s + 1);
    duke(i,0,n)
    f[i][i] = 1;
    duke(l,1,n - 1)
    {
        duke(i,1,n - 1)
        {
            int j = i + l;
            f[i][j] = (j - i + 1);
            duke(k,i,j - 1)
            {
                if(!get(i,k,k + 1,j))
                    f[i][j] = min(f[i][j],f[i][k] + f[k + 1][j]);
                else
                    f[i][j] = min(f[i][j],f[i][k] + 2 + cal((l + 1) / (k - i + 1)));
            }
        }
    }
    printf("%d\n",f[1][n]);
    return 0;
}

 

posted @ 2018-09-29 22:31  DukeLv  阅读(128)  评论(0编辑  收藏  举报