HDU 4295 4 substrings problem (状态压缩DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4295

题意:给出一个主串S和四个子串,将四个子串放在S的恰当位置,使得最后四个子串覆盖的总字符最小、最大?

输出最小最大值。

思路:f[i][j][k]表示匹配到S的第i个字符,从第i个字符开始向后延伸了j个字符,使用的子串集合为k所得到的

最优值(最小最大,下面以最小为例)。那么对于f[i][j][k],有两种选择:

(1)第i个位置不放任何子串,则f[i+1][j-1][k]=min(f[i+1][j-1][k],f[i][j][k]);

(2)第i个位置放第x(0<=x<4)个子串,长度为len[x],设p=max(j,len[x]),则:

f[i][p][k|1<<x]=max(f[i][p][k|1<<x],f[i][j][k]+p-j);

首先,应该预处理出a[i][j],表示从S的第j个字符开始,可以放第i个子串。(又复习一下KMP。。)

#include <iostream>

#include <cstdio>

#include <string.h>

#define max(x,y) ((x)>(y)?(x):(y))

#define min(x,y) ((x)<(y)?(x):(y))

using namespace std;





const int INF=1000000000;

int a[4][5005],f[5005][75][20];

char s[4][75],str[5005];

int len,L[4];





//子串s,长度L;主串str,长度len

void init(int a[],char s[],int L)

{

    int i,j,next[70];

    next[1]=0;

    for(i=2,j=0;i<=L;i++)

    {

        while(j&&s[j+1]!=s[i]) j=next[j];

        if(s[j+1]==s[i]) j++;

        next[i]=j;

    }



    for(i=1,j=0;i<=len;i++)

    {

        while(j&&s[j+1]!=str[i]) j=next[j];

        if(s[j+1]==str[i]) j++;

        if(j==L) a[i-j+1]=1,j=next[j];

    }

}



int DP1()

{

    int i,j,k,t,p,ans=INF;

    for(i=0; i<=len; i++) for(j=0; j<=70; j++) for(k=0; k<20; k++)

                f[i][j][k]=INF;

    for(i=1; i<=len; i++)

    {

        f[i][0][0]=0;

        for(j=0; j<=64; j++)

        {

            for(k=0; k<15; k++) if(f[i][j][k]!=INF)

            {

                t=max(j-1,0);

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

                for(p=0; p<4; p++) if(0==(k&(1<<p))&&a[p][i])

                {

                    t=max(j,L[p]);

                    f[i][t][k|1<<p]=min(f[i][t][k|1<<p],f[i][j][k]+t-j);

                }

            }

            ans=min(ans,f[i][j][15]);

        }

    }

    return ans;

}



int DP2()

{

    int i,j,k,t,p,ans=0;

    for(i=0; i<=len; i++) for(j=0; j<=70; j++) for(k=0; k<=15; k++)

                f[i][j][k]=-INF;

    for(i=1; i<=len; i++)

    {

        f[i][0][0]=0;

        for(j=0; j<=64; j++)

        {

            for(k=0; k<15; k++) if(f[i][j][k]!=-INF)

            {

                t=max(j-1,0);

                f[i+1][t][k]=max(f[i+1][t][k],f[i][j][k]);

                for(p=0; p<4; p++) if(0==(k&(1<<p))&&a[p][i])

                {

                    t=max(j,L[p]);

                    f[i][t][k|1<<p]=max(f[i][t][k|1<<p],f[i][j][k]+t-j);

                }

            }

            ans=max(ans,f[i][j][15]);

        }

    }

    return ans;

}





int main()

{

    while(scanf("%s",str+1)!=-1)

    {

        memset(a,0,sizeof(a));

        len=strlen(str+1);

        int i;

        for(i=0; i<4; i++)

        {

            scanf("%s",s[i]+1);

            L[i]=strlen(s[i]+1);

            init(a[i],s[i],L[i]);

        }

        printf("%d %d\n",DP1(),DP2());

    }

    return 0;

}

  

 

你可能感兴趣的:(substring)