BZOJ1212: [HNOI2004]L语言(Trie图+DP)
Description
标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的。现在你要处理的就是一段没有标点的文章。 一段文章T是由若干小写字母构成。一个单词W也是由若干小写字母构成。一个字典D是若干个单词的集合。 我们称一段文章T在某个字典D下是可以被理解的,是指如果文章T可以被分成若干部分,且每一个部分都是字典D中的单词。 例如字典D中包括单词{‘is’, ‘name’, ‘what’, ‘your’},则文章‘whatisyourname’是在字典D下可以被理解的 因为它可以分成4个单词:‘what’, ‘is’, ‘your’, ‘name’,且每个单词都属于字典D,而文章‘whatisyouname’ 在字典D下不能被理解,但可以在字典D’=D+{‘you’}下被理解。这段文章的一个前缀‘whatis’,也可以在字典D下被理解 而且是在字典D下能够被理解的最长的前缀。 给定一个字典D,你的程序需要判断若干段文章在字典D下是否能够被理解。 并给出其在字典D下能够被理解的最长前缀的位置。
Input
输入文件第一行是两个正整数n和m,表示字典D中有n个单词,且有m段文章需要被处理。 之后的n行每行描述一个单词,再之后的m行每行描述一段文章。 其中1<=n, m<=20,每个单词长度不超过10,每段文章长度不超过1M。
Output
对于输入的每一段文章,你需要输出这段文章在字典D可以被理解的最长前缀的位置。
Sample Input
4 3
is
name
what
your
whatisyourname
whatisyouname
whaisyourname
is
name
what
your
whatisyourname
whatisyouname
whaisyourname
Sample Output
14
6
0
6
0
解题思路:
最长可理解前缀,可以认为是在Trie图匹配时维护一个bool型数组
记录匹配成功的单词,若此单词独立,就更新dp数组
代码:
1 #include<queue> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using std::max; 6 struct trnt{ 7 int ch[26]; 8 int fl; 9 int fin; 10 }tr[100000]; 11 char tmp[2000000]; 12 int ln[100]; 13 bool dp[1000000]; 14 int siz; 15 int n,m; 16 std::queue<int>Q; 17 void Insert(char *a,int k,int &len) 18 { 19 len=strlen(a+1); 20 int root=0; 21 for(int i=1;i<=len;i++) 22 { 23 int c=a[i]-'a'; 24 if(!tr[root].ch[c]) 25 tr[root].ch[c]=++siz; 26 root=tr[root].ch[c]; 27 } 28 tr[root].fin=k; 29 return ; 30 } 31 void Build() 32 { 33 int root=0; 34 for(int i=0;i<26;i++) 35 if(tr[root].ch[i]) 36 Q.push(tr[root].ch[i]); 37 while(!Q.empty()) 38 { 39 root=Q.front(); 40 Q.pop(); 41 for(int i=0;i<26;i++) 42 { 43 if(tr[root].ch[i]) 44 { 45 tr[tr[root].ch[i]].fl=tr[tr[root].fl].ch[i]; 46 Q.push(tr[root].ch[i]); 47 }else 48 tr[root].ch[i]=tr[tr[root].fl].ch[i]; 49 } 50 } 51 return ; 52 } 53 int Dp(char *a) 54 { 55 int len=strlen(a+1); 56 for(int i=1;i<=len;i++) 57 dp[i]=0; 58 dp[0]=1; 59 int ans=0; 60 int root=0; 61 for(int i=1;i<=len;i++) 62 { 63 int c=a[i]-'a'; 64 root=tr[root].ch[c]; 65 for(int j=root;j;j=tr[j].fl) 66 if(tr[j].fin&&dp[i-ln[tr[j].fin]]) 67 { 68 dp[i]=true; 69 ans=max(ans,i); 70 break; 71 } 72 } 73 return ans; 74 } 75 int main() 76 { 77 scanf("%d%d",&n,&m); 78 for(int i=1;i<=n;i++) 79 { 80 scanf("%s",tmp+1); 81 Insert(tmp,i,ln[i]); 82 } 83 Build(); 84 while(m--) 85 { 86 scanf("%s",tmp+1); 87 printf("%d\n",Dp(tmp)); 88 } 89 return 0; 90 }