将信息以边的形式储存,如:
0
a / \ b
1 2
c / \d | e
3 4 5
查询“ac”时,遍历0-1-3。
T1 单词化简
#include<cstdio>
#include<iostream>
using namespace std;
int n, tri[2505][30], len;
string s[52];
void insert(const int x) {
int p = 0;
for(int i = 0; i < s[x].length(); i ++) {
int v = s[x][i] - 'a' + 1;
if(! tri[p][v]) {
tri[p][v] = ++ len;//B
tri[p][0] ++;//A
}
p = tri[p][v];
}
}
void dfs(const int x) {
int p = 0;
char tmp = 0;
for(int i = 0; i < s[x].length(); i ++) {
int v = s[x][i] - 'a' + 1;
if(tri[p][0] != 1)
tmp = i;
p = tri[p][v];
}
for(int i = 0; i < s[x].length(); i ++) {
printf("%c", s[x][i]);
if(i == tmp)
break;
}
printf("\n");
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i ++) {
cin >> s[i];
insert(i);
}
for(int i = 1; i <= n; i ++) {
dfs(i);
}
return 0;
}
A:0号位起到统计儿子的作用,注意:前面的v因此要+1。
B:创建新的编号来存字母,注意:后面p=tri[p][v]不能写为p=len。
T2 Phone List
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int len, T, n, tri[100010][13];
string s;
bool f, in[100010];
void insert() {
int p = 0;
for(int i = 0; i < s.length(); i ++) {
int v = s[i] - '0' + 1;
if(! tri[p][v]) {
tri[p][v] = ++ len;
tri[p][0] ++;
}
p = tri[p][v];
}
in[p] = 1;
}
void dfs(const int x) {
if(f || tri[x][0] == 0)
return;
if(in[x]) {
printf("NO\n");
f = 1;
return;
}
for(int i = 1; i <= 10; i ++)
if(tri[x][i])
dfs(tri[x][i]);
}
int main() {
scanf("%d", &T);
while(T --) {
f = 0;
len = 0;
scanf("%d", &n);
memset(tri, 0, sizeof(tri));
memset(in, 0, sizeof(in));
for(int i = 1; i <= n; i ++) {
cin >> s;
insert();
}
dfs(0);
if(! f)
printf("YES\n");
}
return 0;
}
其实就是找在0到被in[]标记过的点的路径中有没有被in[]标记过的点。利用之前的tri[p][0]判断是否为末端点就行了。PS:记得清0!
还算简单吧?如果有问题,请在评论区指出。