您的位置:首页 > 产品设计 > UI/UE

Codeforces Round#201(div1) D. Lucky Common Subsequence

2014-09-09 19:14 701 查看
题意:给定两个串,求出两个串的最长公共子序列,要求该公共子序列不包含virus串。

用dp+kmp实现

dp[i][j][k]表示以i结尾的字符串和以j结尾的字符串的公共子序列的长度(其中k表示该公共子序列的与virus的匹配程度)很显然,当k==strlen(virus)时,该公共子序列不是我们所求得

当添加一个字符时,如果失配,这时不能让k直接等于0,而是要用kmp给k一个合理的值。

#include <stdio.h>
#include <string.h>
const int N = 100 + 10;
int dp

;
int pre

[3];
char s1
,s2
,vir
;
int next
;
char ans
;
void makeNext(int n)
{
next[0] = -1;
int i = 0,j=-1;
while(i < n)
{
if(j==-1 || vir[i] == vir[j])
{
i++;
j++;
next[i] = j;
}
else
j = next[j];
}
}
void DP(int x, int y, int z, int x1, int y1, int z1, int val)
{
if(dp[x][y][z] < dp[x1][y1][z1] + val)
{
dp[x][y][z] = dp[x1][y1][z1] + val;//状态转移
//保存路径
pre[x][y][z][0] = x1;
pre[x][y][z][1] = y1;
pre[x][y][z][2] = z1;
}
}
int main()
{
int i,j,k;
scanf("%s%s%s",s1+1,s2+1,vir);
int len1 = strlen(s1+1);
int len2 = strlen(s2+1);
int len3 = strlen(vir);
memset(dp,0,sizeof(dp));
memset(pre,-1,sizeof(pre));
makeNext(len3);
for(i=1; i<=len1; ++i)
for(j=1; j<=len2; ++j)
{
for(k=0; k<len3; ++k)
{
DP(i,j,k,i-1,j,k,0);//s1[i] != s2[j]时的转移
DP(i,j,k,i,j-1,k,0);
if(s1[i] == s2[j])//s1[i] == s2[j]
{
if(s1[i] == vir[k])
{
DP(i,j,k+1,i-1,j-1,k,1);
}
else
{
int p = next[k];
while(p!=-1 && s1[i] != vir[p]) p = next[p];
if(p==-1)
p = 0;
if(s1[i] == vir[p])
DP(i,j,p+1,i-1,j-1,k,1);
else
DP(i,j,p,i-1,j-1,k,1);
}
}
}
}
int z;
int Max = -1;
for(k=0; k<len3; ++k)
if(Max < dp[len1][len2][k])
{
Max = dp[len1][len2][k];
z = k;
}
if(Max <= 0)
printf("0\n");
else//根据路径求出最长公共子序列
{
int tMax = Max;
int x = len1,y = len2;
while(pre[x][y][z][0] != -1)
{
int xx = pre[x][y][z][0];
int yy = pre[x][y][z][1];
int zz = pre[x][y][z][2];
if(x-xx==1 && y-yy==1&&s1[x] == s2[y])
ans[Max--] = s1[x];
x = xx;y=yy;z=zz;
}
for(i=1; i<=tMax; ++i)
printf("%c",ans[i]);
printf("\n");
}
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: