字典树
何为字典树:
如图所示:
每个字符有很多个分支,打黄色标记的就是字符串的结尾,所以这颗字典树中有哪些字符串呢,"ab","ay","ayf","c","cc","cd",其他的枝没有画全。
如何存储:
顺序存储字符串:“ab”“ay”“ayf”“c”“cc”“cd”……(节点编号讲究先到先得)
数组tree[i][j]:代表i节点的第j个儿子的根编号。(获取第几个孩子可以s[i]-'a',以图中5节点举例,就是tree[0][2]=5)
数组flag[i]:为true代表到该节点为一个字符串
https://blog.csdn.net/TDD_Master/article/details/86688586
Phone List
HDU - 1671 很多电话号码,看有没有一个号码是另一个号码的前缀
思路,看经过的路径上每个点的sum[i]值,如果都大于等于2,说明这个号码是某一个号码的前缀。
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxm = 1e4 + 5; const int maxm2 = 1e5 + 5; int t, n, tot; char ch[maxm][15]; int tree[maxm2][15],sum[maxm2]; void add(char s[]) { int root = 0, len = strlen(s); for(int i = 0; i < len; i++) { int id = s[i] - '0'; if(!tree[root][id]) { memset(tree[tot], 0, sizeof(tree[tot])); sum[tot] = 0; tree[root][id] = tot++; } root = tree[root][id]; sum[root]++; } } bool findx(char s[]) { int root = 0, len = strlen(s), num = 0; for(int i = 0; i < len; i++) { int id = s[i] - '0'; root = tree[root][id]; if(sum[root] >= 2) num++; } if(num == len) return true; return false; } int main() { scanf("%d", &t); while(t--) { scanf("%d", &n); tot = 1; memset(tree[0], 0, sizeof(tree[0])); // memset(tree, 0, sizeof(tree)); // memset(sum, 0, sizeof(sum)); for(int i = 0; i < n; i++) { scanf("%s", ch[i]); add(ch[i]); } int ans = 0; for(int i = 0; i < n; i++) { if(findx(ch[i])) { // printf("%d\n", i); ans = 1; break; } } if(ans) printf("NO\n"); else printf("YES\n"); } return 0; }
HDU 1247 Hat’s Words
看有没有单词是有其他两个单词合并起来的
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxm = 5e4 + 5; const int maxm2 = 1e6 + 5; char s[maxm][20]; int flag[maxm2], tree[maxm][27]; int tot; void add(char ch[]) { int root = 0, id = 0, len = strlen(ch); for(int i = 0; i < len; i++) { id = ch[i] - 'a'; if(!tree[root][id]) { memset(tree[tot], 0, sizeof(tree[tot])); flag[tot] = 0; tree[root][id] = tot++; } root = tree[root][id]; } flag[root] = 1; } bool find2(char ch[]) { int root = 0, id = 0, len = strlen(ch); for(int i = 0; i < len; i++) { id = ch[i] - 'a'; if(!tree[root][id]) return false; root = tree[root][id]; } if(flag[root]) return true; else return false; } bool find1(char ch[]) { int root = 0, id = 0, len = strlen(ch); for(int i = 0; i < len; i++) { id = ch[i] - 'a'; if(flag[root] && find2(ch + i)) return true; root = tree[root][id]; } return false; } int main() { int ant = 0; tot = 1; memset(tree[0], 0, sizeof(tree[0])); while(~scanf("%s", s[ant])) { // if(s[ant][0] == '#') break; add(s[ant]); ant++; } for(int i = 0; i < ant; i++) { // printf("%d\n", find1(s[i])); if(find1(s[i])) printf("%s\n", s[i]); } return 0; }
Remember the Word
这个题使用dp做得,一个单词,看他被输入的那些字符串组成由多少中情况,那些字符长度最多为100.
#include<cstdio> #include<cstring> #define maxnode int(4e5+10) #define sigma_size int(26) #define mod int(20071027) using namespace std; char tmp[200]; char st[maxnode]; int dp[maxnode]; int ch[maxnode][sigma_size]; int val[maxnode]; int sz, len; //struct trie //{ // trie() { } int idx(char c) { return c - 'a'; } void inse(char *s, int v) { int u = 0, n = strlen(s); for (int i = 0; i < n; i++) { int c = idx(s[i]); if (!ch[u][c]) { memset(ch[sz], 0, sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = v; } int fid(char *s, int pos) { int ans = 0; int u = 0; for (int i = pos; i < len&&i<pos+100; i++) { int c = idx(s[i]); if (!ch[u][c]) return ans; u = ch[u][c];
if (val[u]) ans= (dp[i+1] + ans) % mod; } return ans; } //}tree; int main() { int cas=0, n; while (~scanf("%s", st)) { // tree = trie(); sz = 1; memset(ch[0], 0, sizeof(ch[0])); scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%s", tmp); inse(tmp, 1); } len = strlen(st); dp[len] = 1; for (int i = len - 1; i >= 0; i--) { dp[i] = fid(st, i); } printf("Case %d: %d\n",++cas, dp[0]); } return 0; }