bzoj 1819: 电子字典 Trie
题目:
Description
人们在英文字典中查找某个单词的时候可能不知道该单词的完整拼法,而只知道该单词的一个错误的近似拼法,这时人们可能陷入困境,为了查找一个单词而浪费大量的时间。带有模糊查询功能的电子字典能够从一定程度上解决这一问题:用户只要输入一个字符串,电子字典就返回与该单词编辑距离最小的几个单词供用户选择。 字符串a与字符串b的编辑距离是指:允许对a或b串进行下列“编辑”操作,将a变为b或b变为a,最少“编辑”次数即为距离。 删除串中某个位置的字母; 添加一个字母到串中某个位置; 替换串中某一位置的一个字母为另一个字母; JSOI团队正在开发一款电子字典,你需要帮助团队实现一个用于模糊查询功能的计数部件:对于一个待查询字符串,如果它是单词,则返回-1;如果它不是单词,则返回字典中有多少个单词与它的编辑距离为1。
Input
第一行包含两个正整数N (N < = 10,000)和M (M < = 10,000)。 接下来的N行,每行一个字符串,第i + 1行为单词Wi。单词长度在1至20之间。再接下来M行,每行一个字符串,第i + N + 1表示一个待查字符串Qi。待查字符串长度在1至20之间。Wi和Qi均由小写字母构成,文件中不包含多余空格。所有单词互不相同,但是查询字符串可能有重复。 提示:有50%的数据范围:N < = 1,000,M < = 1,000。
Output
输出应包括M行,第i行为一个整数Xi。Xi = -1表示Qi为字典中的单词;否则Xi表示与Qi编辑距离为1的单词的个数。
题解:
其实我们在Trie上直接暴力dfs即可
因为只需要求编辑距离为1的单词个数,实际上并没有那么慢.
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch = getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 210010;
int ch[maxn][26],nodecnt;
bool ed[maxn];
inline void insert(char *s){
int nw = 0;
for(int i=0,c;s[i];++i){
c = s[i] - 'a';
if(ch[nw][c] == 0) ch[nw][c] = ++ nodecnt;
nw = ch[nw][c];
}ed[nw] = true;
}
int vis[maxn],T,len,ans;
bool flag;
char s[maxn];
inline void dfs(int u,int i,int us){
if(i == len && us == 1 && ed[u]){flag = 1;return ;}
if(i == len && us == 0 && ed[u]){
if(vis[u] != T) ++ ans,vis[u] = T;
return;
}
if(i < len && us == 1) dfs(u,i+1,us-1);
if(us == 1){
for(int c=0;c<26;++c){
if(ch[u][c]){
dfs(ch[u][c],i,0);
if(c != (s[i+1]-'a')) dfs(ch[u][c],i+1,0);
}
}
}
if(i == len) return;
if(ch[u][s[i+1]-'a']) dfs(ch[u][s[i+1]-'a'],i+1,us);
}
int main(){
int n,m;read(n);read(m);
for(int i=1;i<=n;++i){
scanf("%s",s);
insert(s);
}
for(T=1;T<=m;++T){
scanf("%s",s+1);len = strlen(s+1);
flag = 0;ans = 0;
dfs(0,0,1);
if(flag) puts("-1");
else printf("%d\n",ans);
}
getchar();getchar();
return 0;
}
(乃们不要问我为什么dfs和qingdaobaibai的那么像)
人就像命运下的蝼蚁,谁也无法操控自己的人生.