zoukankan      html  css  js  c++  java
  • HDU-4300 Clairewd’s message (kmp或扩展kmp)

    题意:给出26个字母对应的映射关系,然后给出一行string
     其中有密文也有明文,明文部分是不完整的 ,输出可能组成的最短明文
    思路:先将(假设整个子串为)暗文全部翻译成明文,然后将翻译后的子串与原串相连接,去匹配最长公共前后缀,这是一种思路(但是会超时)

    例如:
    
    qwertyuiopasdfghjklzxcvbnm
    
    qwertabcde -> jvrkzqwert (转译后)  qwertabcdejvrkzqwert 找公共前后缀长度即可 (但是注意其长度不能超过n/2最长明文长度)
    

    所以换一种思路:我们知道密文的长度至少为n/2,先将其转为明文然后再求最长公共前缀位置kmp然后用len减去(也就是直接使用kmp来求解)
    或者我们再用扩展kmp的算法,来求得模式串(转译后)与原串(转译前)的最长前缀,从而得到所能匹配的明文部分

    kmp代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    
    #define maxn 100005
    
    int nex[maxn];
    
    void getnext(char t[]){//求next数组
        int j,k,len;
        j=0;
        k=-1;
        nex[j]= k;
        len=strlen(t);
        while(j<len){
            if(k==-1||t[j]==t[k]){
                nex[++j] =++k;
            }
            else k=nex[k];
        }
    }
    
    int kmp(char s[],char t[]){//求子串首次出现在主串中的位置
        int i,j,lens,lent;
        i=j=0;
        lens=strlen(s);
        lent=strlen(t);
    
        while(i<lens&&j<lent){
            if(j==-1||s[i]==t[j]){
                ++i;
                ++j;
            }
            else j=nex[j];
        }
        return j;
    }
    
    int main(){
        char str[27],str1[maxn],str2[maxn];
        char cstr[27];//密文->明文
        
        int t,i,len1,len2,num;
        scanf("%d",&t);
    
        while(t--){
            scanf("%s%s",str,str1);
            for(i=0;i<26;++i)
                cstr[str[i]-'a']= 'a'+i;//转换 
                
            len1=strlen(str1);
            for(i=0;i<len1;++i)
                str2[i]=cstr[str1[i]-'a'];//全部转换为明文(假设全部为暗文) 
            
            str2[i]='';
            getnext(str2);//求子串的next数组
            
            len2 = len1/2;//假设串中明文长度
            num = kmp(str1+len1-len2,str2);//从一半后的位置开始匹配(因为可以假设暗文最短为n/2,即明文最长为n/2); 
            printf("%s",str1);
            len2=len1-num;//明文补全长度(从匹配位开始到结束) 
            for(i=num;i<len2;++i){
                printf("%c",str2[i]);
            }
            printf("
    ");
        }
        return 0;
    }

    扩展kmp

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define maxn 100005
    
    using namespace std;
    
    
    char str1[maxn],str2[maxn];
    int nex[maxn],extend[maxn];
    int len1,len2;
    
    //扩展kmp
    
    void getnext(){
        nex[0]=len2;
        int j=0,p;
        while(j+1<len1&&str2[j]==str2[j+1])j++;
        nex[1]=j;
        int k=1;
        for(int i=2;i<len2;i++){
            p=nex[k]+k-1;
            if(i+nex[i-k]-1<p) nex[i]=nex[i-k];
            else{
                j = max(0,p-i+1);
                while(i+j<len2&&str2[i+j]==str2[j])j++;
                nex[i]=j;
                k=i;
            }
        }
    }
    void exkmp(){
        getnext();
        int j=0,p;
        int len = min(len1,len2);
        while(j<len&&str2[j]==str1[j])j++;
        extend[0]=j;
        
        int k=0;
        for(int i=1;i<len1;i++){
            p = extend[k]+k-1;
            if(i+nex[i-k]-1<p) extend[i]=nex[i-k];
            else{
                j=max(0,p-i+1);
                while(i+j<len1&&j<len1&&str1[i+j]==str2[j])j++;
                extend[i]=j;
                k=i;
            }
        }
    }
    
    int main(){
        char str[27];
        char cstr[27];//密文->明文
        int t,i,j,len,num;
        scanf("%d",&t);
    
        while(t--){
            scanf("%s%s",str,str1);
            for(i=0;i<26;++i)
                cstr[str[i]-'a']='a'+i; 
                
            len1=strlen(str1);
            for(i=0;i<len1;++i)
                str2[i]=cstr[str1[i]-'a'];//转译
            str2[i]='';
            len2 = strlen(str2);
            exkmp();
            len =(len1+1)/2;//假设串中密文长度
            for(i=len;i<len1;++i)//从一半+1开始看,因为密文长度大于等于一半
                if(i+extend[i]==len1)break;//此时i为实际密文(明文)长度
           
            printf("%s",str1);
            for(j=len1-i;j<i;++j){
                printf("%c",str2[j]);
            }
            printf("
    ");
        }
        return 0;
    }
  • 相关阅读:
    Andoird注册功能
    android注册功能
    寒假周总结六
    android登录功能
    Android登录功能
    android登录功能
    每日日报2021.1.24
    每日博客2021.1.23
    每日日报2021.1.22
    每日日报2021.1.21
  • 原文地址:https://www.cnblogs.com/Tianwell/p/11248957.html
Copyright © 2011-2022 走看看