POJ 3576 Hash Trie

POJ 3576
题目链接:
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16065
题意:
问怎样按照题目的规则得到最少的点(题意实在是无法描述)
思路:
首先知道Trie树能形成这些单词的字典树。然后就看树上有多少个子树可以合并。
所以问题转换成如何确定以某个点为根节点的子树的Hash值。
本题采用unsigned long long表示Hash值,如果溢出自动剔除高位。然而开脑洞测几种Hash方法,换一下常量就行了。
源码:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
#define ULL unsigned long long
#define LL long long
#define SEED 11198411
const int MAXN = 150000;
const int MAXM = 26;
struct Trie
{
    int son[MAXN][MAXM];
    int cnt, en[MAXN];
    int root;
    char cun[MAXN];
    void init(){
        root = 0;
        cnt = 1;
        memset(en, 0, sizeof(en));
        memset(son, -1, sizeof(son));
    }
    void ins(char *str, int val)
    {
//        printf("str = %s\n", str);
        int pos = root;
        for(int i = 0 ; str[i] != '\0' ; i++){
            int mark = str[i] - 'a';
//            printf("mark = %d\n", mark);
            if(son[pos][mark] == -1){
                cun[cnt] = str[i];
                son[pos][mark] = cnt++;
            }
            pos = son[pos][mark];
            if(str[i + 1] == '\0')
                en[pos] = val;
        }
//        printf("\n");
    }
}tree;
struct Edge
{
    int deep;
    int en;
    ULL hash;
}e[MAXN];
int deep[MAXN];
void dfs(int u)
{
    e[u].deep = 0;
    e[u].hash = 1;
    e[u].en = tree.en[u];
    LL t = 1;
    for(int i = 0 ; i < 26 ; i++){
        if(tree.son[u][i] != -1){
            dfs(tree.son[u][i]);
            e[u].deep = max(e[u].deep, e[tree.son[u][i]].deep);
            e[u].hash = e[u].hash + (e[tree.son[u][i]].hash) * t + tree.cun[tree.son[u][i]] - 'a' + tree.en[tree.son[u][i]];
        }
        t *= 23;
    }
    e[u].deep++;
//    printf("u = %d, deep = %d, hash = %I64u, en = %d, cun = %c\n", u, e[u].deep, e[u].hash, e[u].en, tree.cun[u]);
}
char str[35];
bool cmp(Edge u, Edge v)
{
    if(u.deep != v.deep)    return u.deep < v.deep;
    if(u.hash != v.hash)    return u.hash < v.hash;
    if(u.en != v.en)    return u.en < v.en;
}
int main()
{
//    freopen("POJ 3576.in", "r", stdin);
    int n;
    while(scanf("%d", &n) != EOF){
        tree.init();
        for(int i = 0 ; i < n ; i++){
            scanf("%s", str);
            tree.ins(str, 1);
        }
        dfs(0);
        sort(e, e + tree.cnt, cmp);
//        printf("tree.cnt = %d\n", tree.cnt);
        int ans = 0;
        for(int i = 1 ; i < tree.cnt ; i++){
            if(e[i].hash != e[i - 1].hash || e[i].deep != e[i-1].deep || e[i].en != e[i-1].en)
                ans++;
        }
        printf("%d\n", ans + 1);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值