HDU_4295

    可以用f[i][j][k]表示递推到S的第i个字符时,选取的字符串的集合为k(用二进制表示),从当前字符开始向后已经覆盖了长度j的字符。

    在这里不妨只讨论最小覆盖长度,最大覆盖长度类似。为了方便dp所以选用刷表的方式,首先令f[i][0][0]为0,接着对于任意一个f[i][j][k],实际上有两种决策,一种是当前这个位置什么也不放就过度到下一个字符,那么就有f[i+1][j-1][k]=std::min(f[i+1][j-1][k],f[i][j][k]),另一种就是从当前位置开始放上字符串t,这时要稍稍讨论一下,因为字符串t的长度可能会影响状态j,也就是从当前字符开始向后已经覆盖了的长度,设放上字符串t后的j的状态为nj,f的值nf,那么就有f[i][nj][k|1<<t]=std::min(f[i][nj][k|1<<t],nf)。

    为了能够方便的知道当前位置能否放上字符串t,就需要预处理出从S的各个位置开始是否能够放上a、b、c、d四个字符串,这里暴力也行KMP也行,反正这部分的复杂度对整体的复杂度来讲影响不大。

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define MAXL 4110
#define INF 0x3f3f3f3f
#define inf 0xc3c3c3c3
char s[MAXL], b[4][70];
int N, P[70], h[4][MAXL], len[4], f[MAXL][70][16];
void KMP(int k)
{
    int i, j;
    P[1] = 0;
    for(i = 2, j = 0; i <= len[k]; i ++)
    {
        while(j && b[k][j + 1] != b[k][i]) j = P[j];
        if(b[k][j + 1] == b[k][i]) ++ j;
        P[i] = j;
    }
    memset(h[k], 0, sizeof(h[k][0]) * (N + 1));
    for(i = 1, j = 0; i <= N; i ++)
    {
        while(j && b[k][j + 1] != s[i]) j = P[j];
        if(b[k][j + 1] == s[i]) ++ j;
        if(j == len[k]) h[k][i - len[k] + 1] = 1, j = P[j];
    }
}
void init()
{
    int i, j, k;
    N = strlen(s + 1);
    for(i = 0; i < 4; i ++)
        scanf("%s", b[i] + 1), len[i] = strlen(b[i] + 1), KMP(i);
}
void dp(int c, const int &(&fun) (const int &, const int &))
{
    int i, j, k, nj, nf, ans = c ? INF : inf;
    memset(f, c ? 0x3f : 0xc3, sizeof(f[0]) * (N + 1));
    for(i = 1; i <= N; i ++)
    {
        f[i][0][0] = 0;
        for(j = 0; j <= 64; j ++)
        {
            for(k = 0; k < 15; k ++)
                if(f[i][j][k] != (c ? INF : inf))
                {
                    int nj = j > 0 ? j - 1 : 0;
                    f[i + 1][nj][k] = fun(f[i + 1][nj][k], f[i][j][k]);
                    for(int t = 0; t < 4; t ++)
                        if((k & 1 << t) == 0 && h[t][i])
                        {
                            nj = std::max(j, len[t]);
                            f[i][nj][k | 1 << t] = fun(f[i][nj][k | 1 << t], f[i][j][k] + nj - j);
                        }
                }
            ans = fun(ans, f[i][j][15]);
        }
    }
    printf("%d", ans);
}
void solve()
{
    dp(1, std::min), printf(" "), dp(0, std::max), printf("\n");
}
int main()
{
    while(scanf("%s", s + 1) == 1)
    {
        init();
        solve();
    }
    return 0;
}

 

 

 

posted on 2012-09-18 21:57  Staginner  阅读(328)  评论(0编辑  收藏  举报