hdu 4300(kmp)

题意:说实话这个题的题意还真的挺难懂的,我开始看了好久都没看懂,后来百度了下题意才弄懂了,这题的意思就是首先有一个字母的转换表,就是输入的第一行的字符串,就是'a'转成第一个字母,'b'转成转换表的第二个字母·······然后下面一个字符串是密文+明文的形式的字符串。就是说前后两段是重复的,只不过通过转换表转换了下。而且后面一段可能不完整,让我们补完整。

思路:这道题我很久之前就已经a掉了,当时是用普通的kmp做的,稍微变通下就行了。只不过现在正在学习扩展kmp,所以就用扩展kmp做了下,个人觉得普通的kmp还好一点,代码短也容易理解。

我现在讲两种方法:

第一种、普通的kmp首先题目中输入的字符串:密文+明文,假设该字符串为s1,第一步:把s1全部翻译一遍变成:明文+密文,假设该字符串为s2;第二步:我们以s1的后半段为主串,以s2为模式串进行kmp即可。

代码实现:

#include<iostream>
#include<cstring>
using namespace std;
char a[100001],c[100001];
int next[100001];
int main()
{
    int T,i,j,len,nima[27],mid;
    char b[27];
    while(scanf("%d",&T)!=EOF)
    {
        getchar();
        while(T--)
        {
            scanf("%s%s",b+1,a+1);
            for(i=1;i<=26;i++)
               nima[b[i]-'a']=i-1;
            len=strlen(a+1);
            for(i=1;i<=len;i++)
                c[i]='a'+nima[a[i]-'a'];
            i=1;j=0;next[1]=0;
            while(i<len)
            {
                if(j==0||c[i]==c[j])
                {
                    i++;j++;
                    next[i]=j;
                }
                else
                    j=next[j];
            }
            if(len%2==0)
                i=len/2+1;
            else
                i=len/2+2;
            j=1;mid=i;
            while(i<=len)
            {
                if(j==0||a[i]==c[j])
                {
                    i++;j++;
                    
                }
                else
                    j=next[j];
            }
            for(i=1;i<=len;i++)
                printf("%c",a[i]);
            for(i=j;i<j+len-2*j+2;i++)
                printf("%c",c[i]);
            printf("\n");
        }
    }
    return 0;
}

 

第二种、扩展kmp,首先题目中输入的字符串:密文+明文,假设该字符串为s1,第一步:把s1 的后半段翻译译一遍变成:假设该字符串为s2;第二步:以s1为主串,s2为模式串进行一次扩展kmp,得到extend数组;第三步:对extend数组进行一次扫描,如果主串某一位置的后缀与模式串的前缀全部匹配就立即停止,这一位置就是满足的最优解了。

代码实现:

#include<stdio.h>
#include<string.h>
char str1[26],T[100005];
char s1[26],S[100005];
int next[100005],extend[100005];
void get_next()
{
    int len=strlen(T),j,a,k,p,L;
    next[0]=len;
    a=0;
    while(a<len-1&&T[a]==T[a+1])
        a++;
    next[1]=a;
    a=1;
    for(k=2;k<len;k++)
    {
        p=a+next[a]-1;
        L=next[k-a];
        if(k+L-1>=p)
        {
            j=p-k+1>0?p-k+1:0;
            while(j+k<len&&T[j+k]==T[j])
                j++;
            next[k]=j;
            a=k;
        }
        else
            next[k]=L;
    }
}
void get_extend()//S为主串,T为模式串
{
    int len1,len2,len,j,k,a,p,L;
    get_next();
    len1=strlen(S);
    len2=strlen(T);
    len=len1>len2?len2:len1;
    a=0;
    while(a<len&&S[a]==T[a])
        a++;
    extend[0]=a;
    a=0;
    for(k=1;k<len1;k++)
    {
        p=a+extend[a]-1;
        L=next[k-a];
        if(k+L-1>=p)
        {
            j=p-k+1>0?p-k+1:0;
            while(j+k<len1&&j<len2&&S[j+k]==T[j])
                j++;
            extend[k]=j;
            a=k;
        }
        else
            extend[k]=L;
    }
}
int main()
{
    int t,i,len,mid,max,len1;
    while(scanf("%d",&t)!=EOF)
    {
        getchar();
        while(t--)
        {
            max=-1;
            scanf("%s",str1);
            scanf("%s",T);
            for(i=0;i<26;i++)
                s1[str1[i]-'a']=i+'a';
            len=strlen(T);
            if(len%2==0)
                mid=len/2;
            else
                mid=len/2+1;
            for(i=mid;i<len;i++)
                S[i-mid]=str1[T[i]-'a'];
            S[i-mid]='\0';
            get_extend();
            len=strlen(S);
            len1=strlen(T);
            for(i=0;i<len;i++)
                if(i+mid+extend[i]==len1)
                {
                    max=extend[i];
                    break;
                }
            printf("%s",T);
            if(max==-1)
                max=0;
            len=strlen(T);
            for(i=max;i<len-max;i++)
                printf("%c",s1[T[i]-'a']);
            printf("\n");
        }
    }
    return 0;
}

 

posted on 2013-07-13 17:31  后端bug开发工程师  阅读(1983)  评论(0编辑  收藏  举报

导航