zoukankan      html  css  js  c++  java
  • Trie 树

    Description

    字母( (Trie) )树是一个表示一个字符串集合中所有字符串的前缀的数据结构,其有如下特征:

    1. 树的每一条边表示字母表中的一个字母

    2. 树根表示一个空的前缀

    3. 树上所有其他的节点都表示一个非空前缀,每一个节点表示的前缀为树根到该节点的路径上所有字母依次连接而成的字符串。

    4. 一个节点的所有出边(节点到儿子节点的边)中不存在重复的字母

    现在 (Matej) 手上有 (N) 个英文小写字母组成的单词,他想知道,如果将这 (N) 个单词中的字母分别进行重新排列,形成的字母树的节点数最少是多少。

    Input

    第一行包含一个正整数 (N)(1le Nle 16)

    接下来 (N) 行每行一个单词,每个单词都由小写字母组成。

    单词的总长度不超过 (1000000)

    Output

    输出仅一个正整数表示 (N) 个单词经过重新排列后,字母树的最少节点数。

    Sample

    Sample Input

    3
    a
    ab
    abc
    

    Sample Output

    4
    

    Sample Input

    3
    a
    ab
    c
    

    Sample Output

    4
    

    Sample Input

    4
    baab
    abab
    aabb
    bbaa
    

    Sample Output

    5
    

    Solution

    显然一道题的正确做法不是它的题面,这道题的空间限制是 (64 MB) 想建一个 (AC) 自动机什么的老搞一搞的就别想了。

    集合动规, (f[S]) 表示将集合 (S) 里的所有串重排后建 Trie 的最小节点数。转移是这样的 $$f[S] = min{ f[k] + f[S oplus k] } - S中字符串公共部分长度$$

    #include<bits/stdc++.h>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    
    int n, S, f[70000], g[200], cnt[20][200];
    char s[1000001];
    
    int main() {
    	scanf("%d", &n); S = (1 << n) - 1;
    	rep(i, 1, n) {
    		scanf("%s", s); int len = strlen(s);
    		rep(j, 0, len - 1) cnt[i][s[j]]++;
    	}
    	rep(i, 1, S) {
    		memset(g, 127, sizeof g); int sum = 0;
    		rep(j, 1, n) if (i & (1 << j - 1)) rep(k, 'a', 'z') f[i] += cnt[j][k], g[k] = min(g[k], cnt[j][k]);
    		rep(j, 'a', 'z') sum += g[j];
    		for (int j = i & i - 1; j; j = i & j - 1) f[i] = min(f[i], f[i ^ j] + f[j]);
    		if (f[i] > sum) f[i] -= sum;
    	}
    	printf("%d", f[S] + 1);
    	return 0;
    }
    
  • 相关阅读:
    有7g和2g的砝码各一个,怎样称可以3次把140g东西分为50g和90g???????
    中缀到后缀(一个例子)
    动态代理模式的使用
    代理模式用来初始化的延迟下载
    ReentrantLock Condition 实现消费者生产者问题
    Two Sum
    [leetcode]重建二叉树(先序和终须) 中序遍和后续
    (转载)旋转数组查找 最简洁方法 总结
    [不明觉厉] 下一个排列
    codeforces -- 283A
  • 原文地址:https://www.cnblogs.com/aziint/p/8462477.html
Copyright © 2011-2022 走看看