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;
    }
  • 相关阅读:
    Windows Azure Storage (17) Azure Storage读取访问地域冗余(Read Access – Geo Redundant Storage, RA-GRS)
    SQL Azure (15) SQL Azure 新的规格
    Azure China (5) 管理Azure China Powershell
    Azure China (4) 管理Azure China Storage Account
    Azure China (3) 使用Visual Studio 2013证书发布Cloud Service至Azure China
    Azure China (2) Azure China管理界面初探
    Azure China (1) Azure公有云落地中国
    SQL Azure (14) 将云端SQL Azure中的数据库备份到本地SQL Server
    [New Portal]Windows Azure Virtual Machine (23) 使用Storage Space,提高Virtual Machine磁盘的IOPS
    Android数据库升级、降级、创建(onCreate() onUpgrade() onDowngrade())的注意点
  • 原文地址:https://www.cnblogs.com/Tianwell/p/11248957.html
Copyright © 2011-2022 走看看