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");
    }
}
原文地址:https://www.cnblogs.com/Norlan/p/4759515.html