hdu KMP + DP

题意 :hdu 4295给出一个母串,长度不超过4096, 两外有4个字串(都是母串的字串),这四个串可以覆盖到母串中,当然可以重叠,现在想求最多与最小能覆盖多少个字符。

 

思路: 这道题是一个看起来不难的题,但是其实却很难的题。  首先预处理出字串能否放到第i个字符的位置。这里可以用KMP预处理。 用数组can[i][j]表示。

接下来是一个DP, 其实最大和最小是一个思想,这里一最小为例, dp[i][j][k],表示处理到第i个字符,k表示状态,表示用了那一个字串,从当前位置还以往后放j个字符的答案。

面对每一个状态,一共有两种选择,一种是不放,继续往前走,那么

                                         dp[i+1][j-1][k] = min(dp[i+1][j-1][k], dp[i][j][k])

还有另外一种选择就是重新放一个字串,那么这时间的方程式 t = max(j,len[m]);

                                         dp[i+1][t][k|(1<<m)] = min(dp[i+1][t][k|(1<<m)],

                                                                                   dp[i][j][k]-j+len[m]);

但是这道题有一个比较坑爹的地方, 就是卡常数, 在更新的时候要判断一下dp[i][j][k]!=INF,在更新,否则就会tle

AC代码:

 

View Code
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int N = 4110, BN = 70, INF = 1<<29;

bool can[4][N];
int len[4], dpx[N][BN][20],dpn[N][BN][20];
int next[N];
char ss[N], s[4][BN];

void getcan(char *s, int lc, bool *can)
{
    next[0]=-1;
    int j=-1;
    for(int i=1; i<lc; i++)
    {
        while(j != -1 && s[i] != s[j+1])
            j = next[j];
        if(s[i] == s[j+1])
            j++;
        next[i]=j;
    }

    int len = strlen(ss+1);
    j = -1;
    for(int i=1; i<=len; i++)
    {
        while(j!=-1 && ss[i]!=s[j+1])
            j = next[j];
        if(ss[i] == s[j+1])
        {
            j++;
            if(j == lc-1)
            {
                can[i-j] = 1;
                j=next[j];
            }
        }
        else j=-1;
    }
}

void init()
{
    memset(can, 0, sizeof(can));
    for(int i=0; i<4; i++)
    {
        scanf("%s", s[i]);
        len[i] = strlen(s[i]);
        getcan(s[i], len[i], can[i]);
    }
}

int min(int a, int b)
{
    return a > b ? b:a;
}

int max(int a, int b)
{
    return a > b ? a:b;
}

void DP1()
{
    int n = strlen(ss+1), ans = INF, t;
    for(int i=0; i<=n; i++)
    {
        for(int j=0; j<=64; j++)
        {
            for(int k=0; k<16; k++)
            {
                dpn[i][j][k] = INF;
            }
        }
        dpn[i][0][0] = 0;
    }

    for(int i=1; i<=n; i++)
    {
        for(int j=0; j<=64; j++)
        {
            for(int k=0; k<15; k++) if(dpn[i][j][k] != INF)
            {
                if(j)
                    dpn[i+1][j-1][k] = min(dpn[i+1][j-1][k],
                                           dpn[i][j][k]);
                else
                    dpn[i+1][j][k] = min(dpn[i+1][j][k],
                                         dpn[i][j][k]);
                for(int m=0; m<4; m++)
                {
                    if( ((1<<m)&k) || (!can[m][i]) ) continue;
                    t = max(j, len[m]);
                    dpn[i][t][k|(1<<m)] = min
                     (dpn[i][t][k|(1<<m)],dpn[i][j][k]-j+t);
                }
            }
            ans = min(ans,dpn[i][j][15]);
        }
    }
    printf("%d ",ans);
}

void DP2()
 {
    int n = strlen(ss+1), ans = -INF, t;
    for(int i=0; i<=n; i++)
    {
        for(int j=0; j<=64; j++)
        {
            for(int k=0; k<16; k++)
            {
                dpx[i][j][k] = -INF;
            }
        }
        dpx[i][0][0] = 0;
    }

    for(int i=1; i<=n; i++)
    {
        for(int j=0; j<=64; j++)
        {
            for(int k=0; k<15; k++) if(dpx[i][j][k] != -INF)
            {
                if(j)
                    dpx[i+1][j-1][k] = max(dpx[i+1][j-1][k],
                                           dpx[i][j][k]);
                else
                    dpx[i+1][j][k] = max(dpx[i+1][j][k],
                                           dpx[i][j][k]);
                for(int m=0; m<4; m++)
                {
                    if( ((1<<m)&k) || (!can[m][i]) ) continue;
                    t = max(j, len[m]);
                    dpx[i][t][k|(1<<m)] = max
                      (dpx[i][t][k|(1<<m)],dpx[i][j][k]-j+t);
                }
            }
           ans = max(ans, dpx[i][j][15]);
        }
    }
    printf("%d\n", ans);
 }

int main()
{
    while(scanf("%s",ss+1) == 1)
    {
        init();
        DP1();
        DP2();
    }
    return 0;
}

 

 

 

 

posted @ 2012-09-19 19:22  Gu Feiyang  阅读(263)  评论(0)    收藏  举报