题目链接: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;
}