传送门:QAQ
题意:实现一个单词补全功能的最小操作步数
思路:对于读入的单词表,我们可以预处理出到达每个前缀所需要的最小步数,这我们可以实现建立一颗字典树,然后在字典树上跑bfs即可。
预处理完后,我们对于读入的单词,只要遍历它的每个前缀统计最小次数即可。
附上代码:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<map>
#include<queue>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
const int MAX_NODE = 1100000 + 10;
const int MAXM=1e5+10;
const int CHARSET = 26;
int trie[MAX_NODE][CHARSET];
char ch[MAX_NODE];
int CharCnt[MAX_NODE];
int vis[MAX_NODE];
int num[MAX_NODE];
int cnt = 1;
vector<int>gx[MAX_NODE];
void insert(char *w) {
int len = strlen(w);
int p = 0;
for (int i = 0; i < len; i++) {
int c = w[i] - 'a';
if (!trie[p][c]) {
trie[p][c] = cnt;
CharCnt[cnt] = 0;
cnt++;
}
CharCnt[trie[p][c]]++;
gx[p].push_back(trie[p][c]);
gx[trie[p][c]].push_back(p);
p = trie[p][c];
}
int id = 0;
for (int i = 0; i < len; i++) {
int c = w[i] - 'a';
if (CharCnt[trie[id][c]] == 1) {
gx[p].push_back(trie[id][c]);
gx[trie[id][c]].push_back(p);
break;
}
id = trie[id][c];
}
}
void bfs() {
queue<int>q;
q.push(0);
num[0] = 0;
vis[0] = 1;
while (!q.empty()) {
int st = q.front();
vis[st] = 1;
q.pop();
for (int i = 0; i < gx[st].size(); i++) {
if (vis[gx[st][i]]) continue;
if (num[gx[st][i]] > num[st] + 1) {
num[gx[st][i]] = num[st] + 1;
q.push(gx[st][i]);
}
}
}
}
void init() {
cnt = 1;
memset(trie, 0, sizeof(trie));
memset(vis, 0, sizeof(vis));
for (int i = 0; i < MAX_NODE; i++) {
num[i] = inf;
}
}
int main(void) {
int n, m;
init();
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
scanf("%s", ch);
insert(ch);
}
bfs();
for (int i = 0; i < m; i++) {
scanf("%s", ch);
int len = strlen(ch);
int id = 0, min_ans = len;
for (int i = 0; i < len; i++) {
int w = ch[i] - 'a';
if (!trie[id][w]) break;
id = trie[id][w];
min_ans = min(min_ans, num[id] + len-1 - i);
//printf("%c**%d**\n", ch[i], num[id]);
}
printf("%d\n", min_ans);
}
}