2.3.1 Longest Prefix 最长前缀(字典树)

版权声明:转载请告知博主并要注明出处嗷~ https://blog.csdn.net/Akatsuki__Itachi/article/details/82775526

Description

在生物学中,一些生物的结构是用包含其要素的大写字母序列来表示的。生物学家对于把长的序列分解成较短的(称之为元素的)序列很感兴趣。 如果一个集合 P 中的元素可以通过串联(允许重复;串联,相当于 Pascal 中的 “+” 运算符)组成一个序列 S ,那么我们认为序列 S 可以分解为 P 中的元素。并不是所有的元素都必须出现。举个例子,序列 ABABACABAAB 可以分解为下面集合中的元素: {A, AB, BA, CA, BBC} 序列 S 的前面 K 个字符称作 S 中长度为 K 的前缀。设计一个程序,输入一个元素集合以及一个大写字母序列,计算这个序列最长的前缀的长度。

Input

输入数据的开头包括 1..200 个元素(长度为 1..10 )组成的集合,用连续的以空格分开的字符串表示。字母全部是大写,数据可能不止一行。元素集合结束的标志是一个只包含一个 “.” 的行。集合中的元素没有重复。接着是大写字母序列 S ,长度为 1..200,000 ,用一行或者多行的字符串来表示,每行不超过 76 个字符。换行符并不是序列 S 的一部分。

Output

只有一行,输出一个整数,表示 S 能够分解成 P 中元素的最长前缀的长度。

Sample Input

A AB BA CA BBC

ABABACABAABC

Sample Output

11

题意也是不好理解啊。。。

意思就是:从第一个集合里,选任意个元素组成一个字符串,这些元素可以重复,也可以不选。问组成的这样的字符串在第二个串里的最长前缀是多少!


按照输入的单词构造字典树,并且在每一个单词的末尾节点标记。

对给定的模式串在字典树上进行查找。

查找的过程是这样的,从第一个字母遍历到最后一个字母,每一次都做一次(从当前下标 i 到字符串末尾)的查找(或者说是匹配)。设一个新的数组 is[ i ] 代表当前下标之前的子串能否满足题目的最长前缀。

那么如果is[i]==true,就代表 i 之前的子串一定满足题目条件的最长前缀。

模拟一下过程:

现命名第二个串为模式串,第一个串里的单词为元素。

从下标0开始,发现元素A和AB在模式串里,那么标记 is[0]和is[1],代表暂时能够组合成ABA这个前缀,以此类推。

到了下标5的时候,发现is[4] 为1,那么继续匹配,标记is[6],但此时is[5]是不标记的,因为ABABAC这个串是组合不了的,但是ABABACA又能组合,所以标记is[6]......

通过上述过程我们可以发现,只要is[i-1]被标记,那么就可以去字典树上做一遍匹配。

最后找到最后一个is[i]=1的下标输出i+1即可。


(还是比较裸的字典树

此题还有很多种解法,dp,记忆化搜索,ac自动机。这儿就不写了(我可能不会写- -!),因为师弟问,才做了这道题- -。

小插曲:一开始T了,后来发现是一开始因为字符串的长度我每次都写的strlen(str),后来改掉就过了2333


#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#define memset(a,v)  memset(a,v,sizeof(a))
#define max(a,b)   (a>b?a:b)
#define min(a,b)   (a<b?a:b)
#define swap(a,b)  (a=a+b,b=a-b,a=a-b)
#define eps 1.0E-8
using namespace std;
const int MAXL(2*1e5);
const int INF(0x7f7f7f7f);
const int mod(1e9+7);
typedef long long int LL;
int trie[MAXL+50][30];
bool ed[MAXL+50];
bool is[MAXL+50];
char word[12];
char str[MAXL+50];
char s[80];
int tot,len;
void buildTree()
{
    int root=0;
    for(int i=0;i<strlen(word);i++)
    {
        int id=word[i]-'A';
        if(!trie[root][id])
            trie[root][id]=++tot;
        root=trie[root][id];
    }
    ed[root]=true;
}
void wordSearch(int k)
{
    int root=0;
    for(int i=k;i<len;i++)
    {
        int id=str[i]-'A';
        if(!trie[root][id])
            return;
        root=trie[root][id];
        if(ed[root]==true)
            is[i]=true;
    }
}
int main()
{
    while(scanf("%s",word))
    {
        if(word[0]=='.') break;
        buildTree();
    }
    while(~scanf("%s",s))
        strcat(str,s);
    len=strlen(str);
    wordSearch(0);
    for(int i=1;i<len;i++)
        if(is[i-1]==true)
            wordSearch(i);
    int ans=0;
    /*
    for(int i=0;i<len;i++)
        cout<<is[i]<<" ";
    cout<<endl;
    */
    for(int i=len-1;i>=0;i--)
        if(is[i]==true){
            ans=i+1;break;
        }
    cout<<ans<<endl;
}


/*
A AB BA CA BBC
.
ABABACABAABC
*/

猜你喜欢

转载自blog.csdn.net/Akatsuki__Itachi/article/details/82775526