hust1350Trie【字典树+dfs || 字典树 + LCA】

大意:告诉你一些字符串 让你组成字典树,

然后定义每个节点到所有叶子节点的距离的和等于改点的value

当根节点只有一个孩子,该根节点也算一个叶子节点

问所有节点的value的最小值

分析:

开始做的时候  就想的是   枚举每个点  然后求它到所有叶子节点的和  求任意两点的最近距离  用公共祖先来求

于是就有了这个算法

需要预处理出来所有的叶子节点

不能单纯的用字典树的flag来记录  例如插入aaa aa a  那么 a  aa aaa 都会被当成叶子节点

对于这里的处理 我是排了一次序  把节点的最后值用flag标记

然后就是判断根节点是否只有一个孩子

如果只有孩子  那么就加入孩子节点的数组

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<queue>
  6 #include<vector>
  7 #include <set>
  8 using namespace std;
  9
 10 const int MAXN = 100010;
 11 const int PP = 30;
 12 const int maxn = MAXN;
 13
 14
 15 int tire[maxn][30];
 16 int flag[maxn];
 17 int ceng[maxn];
 18
 19 class LCA_RMQ
 20 {
 21 public:
 22     int n;
 23     int pow2[PP];
 24     int tim;
 25     int first[MAXN];
 26     int nodeId[MAXN*2];
 27     int dep[MAXN*2];
 28     int dp[MAXN*2][PP];
 29     bool vis[MAXN];
 30     vector<int> edge[MAXN];
 31
 32     void init(int n)
 33     {
 34         for(int i = 0; i < PP; i++)
 35             pow2[i] = (1<<i);
 36
 37         for(int i = 0; i <= n; i++)
 38         {
 39             edge[i].clear();
 40             vis[i] = false;
 41         }
 42
 43     }
 44
 45     void addedge(int u ,int v)
 46     {
 47         edge[u].push_back(v);
 48     }
 49
 50     void dfs(int u ,int d)
 51     {
 52         tim++;
 53         vis[u] = true;
 54         nodeId[tim] = u;
 55         first[u] = tim;
 56         dep[tim] = d;
 57         int sz = edge[u].size();
 58         for(int i = 0; i < sz; i++)
 59         {
 60             int v = edge[u][i];
 61             if(vis[v] == false)
 62             {
 63                 dfs(v, d + 1);
 64                 tim++;
 65                 nodeId[tim] = u;
 66                 dep[tim] = d;
 67             }
 68         }
 69     }
 70
 71     void ST(int len)
 72     {
 73         int k = (int)(log(len+1.0) / log(2.0));
 74
 75         for(int i = 1; i <= len; i++)
 76             dp[i][0] = i;
 77
 78         for(int j = 1; j <= k; j++)
 79             for(int i = 1; i + pow2[j] - 1 <= len; i++)
 80             {
 81                 int a = dp[i][j-1];
 82                 int b = dp[i+pow2[j-1]][j-1];
 83                 if(dep[a] < dep[b]) dp[i][j] = a;
 84                 else dp[i][j] = b;
 85             }
 86     }
 87
 88     int RMQ(int x ,int y)
 89     {
 90         int k = (int)(log(y-x+1.0) / log(2.0));
 91         int a = dp[x][k];
 92         int b = dp[y-pow2[k]+1][k];
 93         if(dep[a] < dep[b]) return a;
 94         else return b;
 95     }
 96
 97     int LCA(int u ,int v)
 98     {
 99         if(u > v) swap(u, v);
100         int x = first[u];
101         int y = first[v];
102         if(x > y) swap(x,y);
103         int index = RMQ(x,y);
104         return nodeId[index];
105     }
106 };
107 LCA_RMQ t;
108
109 int tot;
110 void Insert(string s,int rt)
111 {
112     ceng[rt] = 0;
113     int len=s.length();
114     for(int i=0;i<len;i++)
115     {
116         int x=s[i]-‘a‘;
117         if(tire[rt][x]==0) {
118             tire[rt][x]=tot++;
119             ceng[tire[rt][x]] = i + 1;
120             t.addedge(rt, tire[rt][x]);
121         }
122 //rt        printf("%c %d  %d\n", x + ‘a‘, tire[rt][x], ceng[tire[rt][x]]);
123         rt=tire[rt][x];
124         flag[rt] = 0;
125     }
126     flag[rt]=1;
127 }
128
129 char str[55][15];
130 set<string> ss;
131 int ye[maxn];
132 int main()
133 {
134     int tt;
135     scanf("%d",&tt);
136     for(int kase = 1; kase <= tt; kase++) {
137         int n;
138         scanf("%d",&n);
139         tot = 1;
140         memset(tire, 0, sizeof(tire));
141         memset(flag, 0, sizeof(flag));
142         memset(ceng, 0, sizeof(ceng));
143         tot = 2;
144         t.init(100000);
145         ss.clear();
146         string s1;
147         for(int i = 0; i < n; i++) {
148             getchar();
149             cin >> s1;
150             ss.insert(s1);
151         }
152
153     set<string>::iterator it;
154 for(it = ss.begin(); it != ss.end(); it++) {
155     s1 = *it;
156     Insert(s1, 1);
157 }
158         t.n = tot;
159         t.tim = 0;
160         t.dfs(1, 1);
161         t.ST(2 * t.n - 1);
162         int ye_tot = 0;
163         for(int i = 1; i < tot; i++) {
164             if(flag[i] == true) {
165                 ye[ye_tot++] = i;
166             }
167         }
168         int hh = 0;
169         for(int i = 0; i < 26; i++) {
170             if(tire[1][i] != 0) {
171                 hh++;
172             }
173         }
174         if(hh == 1) {
175             ye[ye_tot++] = 1;
176         }
177 //        for(int i = 0; i< ye_tot; i++) {
178 //            printf("%d ", ye[i]);
179 //        }puts("");
180         int ans = 1000000000;
181         for(int i = 1; i < tot; i++) {
182             int sum = 0;
183             for(int j = 0; j < ye_tot; j++) {
184                 int rt = t.LCA(i, ye[j]);
185                 sum += fabs(ceng[i] - ceng[rt]) + fabs(ceng[ye[j]] - ceng[rt]);
186             }
187
188             ans = min(ans, sum);
189         }
190         printf("Case #%d: %d\n",kase, ans);
191     }
192     return 0;
193 }

第二种方法  直接对每个点dfs  由于总共的点数为500个  所用时间复杂度用500*500

代码:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5
 6 const int maxn = 505;
 7
 8
 9 struct Edge {
10     int to, next;
11 }e[maxn];
12 int sum;
13 int head[maxn];
14
15 void add(int u, int v) {
16     e[sum].to = v;
17     e[sum].next = head[u];
18     head[u] = sum++;
19 }
20
21
22 int tire[maxn][30];
23 int tot;
24
25
26 void init() {
27     memset(tire, 0, sizeof(tire));
28     memset(head, 0, sizeof(head));
29     sum = 1;
30     tot = 1;
31 }
32
33 void Insert(char *s, int rt) {
34     for(int i = 0; s[i]; i++) {
35         int x = s[i] - ‘a‘;
36         if(tire[rt][x] == 0) {
37             tire[rt][x] = tot++;
38             add(rt, tire[rt][x]);
39             add(tire[rt][x], rt);
40         }
41 //        printf("%c   %d\n", s[i], tire[rt][x]);
42         rt = tire[rt][x];
43     }
44 }
45
46 int ans;
47
48 int vis[maxn];
49 void dfs(int u, int de) {
50     vis[u] = 1;
51     bool flag = false;
52     for(int i = head[u]; i; i = e[i].next) {
53         int v = e[i].to;
54         if(!vis[v]) {
55             vis[v] = 1;
56             flag = true;
57             dfs(v, de + 1);
58         }
59     }
60     if(flag == false) {
61         ans += de;
62     }
63 }
64
65 int main() {
66     int t, n;
67     char str[15];
68     scanf("%d",&t);
69     int ka = 1;
70     while(t--) {
71         scanf("%d",&n);
72         init();
73         while(n--) {
74             scanf("\n%s",str);
75 //            printf("%s\n",str);
76             Insert(str, 0);
77         }
78         int _ans = 1000000000;
79         for(int i = 0; i < tot; i++) {
80             ans = 0;
81             memset(vis, 0, sizeof(vis));
82             dfs(i, 0);
83             _ans = min(_ans, ans);
84         }
85         printf("Case #%d: %d\n",ka++,_ans);
86     }
87 }

时间: 2024-11-02 02:49:00

hust1350Trie【字典树+dfs || 字典树 + LCA】的相关文章

P2633|主席树+dfs序+树链剖分求lca+离散化

不知道为什么会RE.. 待补 思路:链上求u和v两点路径第k小利用lca就转变为了 U+V-LCA-FA(LCA) 上的第k小,这因为每个点的主席树的root是从其父转移来的.可以用树链剖分求lca:在dfs序上建立主席树将树上问题转变为区间问题,询问的时候用主席树求区间k小值. 终于能写出这种题了,开心! #include<bits/stdc++.h> using namespace std; const int maxn = 1e5+100; int n,m,e = 1,num,ans=0

【Codeforces163E】e-Government AC自动机fail树 + DFS序 + 树状数组

E. e-Government time limit per test:1 second memory limit per test:256 megabytes input:standard input output:standard output The best programmers of Embezzland compete to develop a part of the project called "e-Government" — the system of automa

【BZOJ-2434】阿狸的打字机 AC自动机 + Fail树 + DFS序 + 树状数组

2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2022  Solved: 1158[Submit][Status][Discuss] Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的:l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最

HDU3887(树dfs序列+树状数组)

Counting Offspring Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2424 Accepted Submission(s): 838 Problem DescriptionYou are given a tree, it’s root is p, and the node is numbered from 1 to n. N

hdu-(1298手机相关 dfs+字典树)

题目大意: 在以前,手机输入法很麻烦,因为只有9个键,而字母有26个,所以一个键上同时包含这几个字母,这样的话,为了打出一个字母可能要按几次.比如键5有"JKL", 如果要输入K,那么就要连按两次. 这样的输入法很麻烦.所以一家公司发明了T9技术输入法.这种输入法内置这很多英语单词,它可以根据英语出现的频率,是否存在等信息,每个字母只要按一次,就可以有想要的预选单词. 例如,假设输入法只内置了一个单词"hell", 那么只需要按4355便可以出来. 注意,如果有一个

hdu1247Hat’s Words (组合单词,字典树+DFS)

Problem Description A hat's word is a word in the dictionary that is the concatenation of exactly two other words in the dictionary. You are to find all the hat's words in a dictionary. Input Standard input consists of a number of lowercase words, on

hdu1298 T9(手机输入法,每按一个数字,找出出现频率最高的字串,字典树+DFS)

Problem Description A while ago it was quite cumbersome to create a message for the Short Message Service (SMS) on a mobile phone. This was because you only have nine keys and the alphabet has more than nine letters, so most characters could only be

HDU - 5390 tree 线段树套字典树 (看题解)

HDU - 5390 看到的第一感觉就是树链剖分 + 线段树套字典树, 感觉复杂度不太对. 其实这种路径其实很特殊, 一个点改变只会影响它儿子到根的路径, 并且这种求最优值问题可以叠加. 所以我们修改的时候对对应dfs序打标记, 询问的时候在线段树上从上往下对每个对应区间求个最优值. 这样还会被卡MLE.. 需要分层优化一下. #pragma GCC optimize(2) #pragma GCC optimize(3) #include<bits/stdc++.h> #define LL l

跳跃表,字典树(单词查找树,Trie树),后缀树,KMP算法,AC 自动机相关算法原理详细汇总

第一部分:跳跃表 本文将总结一种数据结构:跳跃表.前半部分跳跃表性质和操作的介绍直接摘自<让算法的效率跳起来--浅谈"跳跃表"的相关操作及其应用>上海市华东师范大学第二附属中学 魏冉.之后将附上跳跃表的源代码,以及本人对其的了解.难免有错误之处,希望指正,共同进步.谢谢. 跳跃表(Skip List)是1987年才诞生的一种崭新的数据结构,它在进行查找.插入.删除等操作时的期望时间复杂度均为O(logn),有着近乎替代平衡树的本领.而且最重要的一点,就是它的编程复杂度较同类