POJ3630——简单Trie树
这个题的意思是说,给出一些字符串,判断是否有字符串是另一个字符串的前缀,当然可以用排序水过,不过这个题拿来练习一下Trie树不错。
这个题在poj的discuss上好多人说必须要静态建树,估计都是用了指针实现的。。不过竞赛中最好不要用指针,所以这里用了刘汝佳大神的数组实现方法,其实Trie树最重要的是每个节点的sz值,以及val值,ch【】【】数组只是作为index来查询有没有这个字符,所以用数组实现时,把ch【】【】数组定义在main外面,多case的话每个case定义一个Trie就好了。。。如果把ch【】【】数组定义在结构体里面就没办法动态建树了。。。为此re,wa,了无数发。。。
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<map> #include<vector> #include<cmath> #define eps 1e-8 using namespace std; const int maxn = 10010; typedef long long ll; const int maxnode = 1e5+10,sigma_size =10;//maxnode和sigma_size的大小要随题意更改 int ch[maxnode][sigma_size]; int val[maxnode]; struct Trie { int sz; Trie(){sz = 1;memset(ch[0],0,sizeof(ch[0]));} int idx(char c) {return c - '0';} bool insert(char *s) { int u = 0,n = strlen(s); int mark = 0; for(int i = 0; i < n; ++i) { int c = idx(s[i]); if(!ch[u][c]){ mark = 1;//这是一个新的节点,说明到现在为止,这个串新开辟了位置,肯定不是之前某个串的前缀 memset(ch[sz],0,sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; if(val[u]) return false;//遇到了之前某个串的结尾。。肯定不符合题意啦。返回false } val[u] = 1; if(!mark) return false;//到插入整个字符了还没有开辟新位置,显然新插入的字符串是之前某个串的前缀 return true; } }; char s[maxn]; int main() { //freopen("in","r",stdin); int T; scanf("%d",&T); while(T--) { int n; bool flag = true; scanf("%d",&n); Trie t; for(int i = 0; i < n; ++i) { scanf("%s",s); if(flag) flag = t.insert(s); } if(!flag) puts("NO"); else puts("YES"); } }