字符串处理——Tire树__LA3942
其实Trie树并没有听上去那么高级。首先它是把所有的单词存到了一棵树里面,说白了,就是按照一个单词的前缀来存。不过这棵树不需要按照严格意义上的树来了,实际上,只需要用ch[u][i]来存就好了,而ch[u][i]代表的就是整棵树,ch[u][i]的值为树的节点值,即时遍历的时间戳。u代表的是当前节点值,ch[u][i]代表的是u的儿子节点中单词'i'代表的节点值,如果ch[u][i]
= 0,那么我们可以认为这个节点不存在,如果不等于0那么我们认为存在。每一个节点除了节点值(时间戳)外,还有一个权值,我们不妨中间节点的权值附成0,单词最后的那个字母对应的节点的权值附成-1,代表这个位置是一个单词。sz代表的就是当前共有的节点总数。insert函数就是插入单词,这个也比较好写。
大白皮上面把Trie树写在了结构体里面,这样好像直接就限制了ch[][]的范围,应该不是以堆的形式来存了。其实完全不需要,看了上面的解释就知道了,不过感觉还是直接定义一个Trie结构体比较好看一点。。。(然而并没有什么卵用)。就用大白皮上面的那道LA_3942为例吧。下面是代码。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define FOR(i,x,y) for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define MOD 20071027
using namespace std;
int ch[4005*105][26],sz,val[4005*105],len[300005],cnt;
int dp[300005];
char s[300005];
void init(){
memset(ch[0],0,sizeof(ch[0]));
sz = 1;
}
void insert(char* str,int v){
int n = strlen(str),u = 0;
FOR(i,0,n){
int c = str[i] - 'a';
if(!ch[u][c]){
memset(ch[sz],0,sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = v;
}
void find(char* str){
cnt = 0;
int n = strlen(str),u = 0;
FOR(i,0,n){
int c = str[i] - 'a';
if(!ch[u][c]) return;
int id = ch[u][c];
if(val[id]) len[cnt++] = (i+1);
u = id;
}
return ;
}
int main(){
//freopen("test.in","r",stdin);
int tCase = 0;
while(~scanf("%s",s)){
printf("Case %d: ",++tCase);
init();
int n;
char str[105];
scanf("%d",&n);
while(n--){
scanf("%s",str);
insert(str,-1);
}
n = strlen(s);
dp[n] = 1;
IFOR(i,n-1,-1){
find(s+i);
dp[i] = 0;
FOR(j,0,cnt){
dp[i] += dp[i+len[j]];
dp[i] %= MOD;
}
}
printf("%d\n",dp[0]);
}
return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

浙公网安备 33010602011771号