第一场-B-Bless You Autocorrect!

题目链接:点击打开链接

(一)题目大意:

  1. 顺序给出n个由小写英文字母组成的单词。
  2. 当你需要输打出一个单词时,你每一次可以进行三种操作(输入完第一个字母以后):
                 i.直接输入下一个英文字母。
                 ii.按“tap”键直接打印出单词列表中第一次以已打入字母序列为前缀的单词:e.g.如果第一次以abb为前缀的单词为abbcd,那么打完字母abb以后按”tab“键可以直接打出abbcd。
                 iii.删除已经打出的最后一个字符。

        给定n个待打印的单词,对于每个单词输出最少需要的按键次数(具体例子请看原题)。

(二)解题思路:
  1. 首先我们需要储存字符串,当然想到了字典树来储存。
  2. 相比一个一个地打出字母,这里主要地区别是可以通过按“tap”键来加速打印,故需要在传统地字典树上做出一定地修改:当存入某个单词时,若某一个字母是第一次出现,那么输入完这个字母以后通过“tap”键便可以直接跳转到单词地结尾,这就是在字典树上地一个加边过程,比如以下例子:

  3. 在建好字典树以后,通过BFS()我们可以求出从根到达每一个节点需要地步数也就是最少地操作次数。上图中地例子可以得到下图所示结果(注意从末节点到中间节点的边为单向边(从中间到末尾打“tap”即可,从末尾到中间只能一个一个删除),相邻节点之间的边为双向边):
  4. 查询地时候沿着单词往下找即可,中途更新最小值。
  5. 时间复杂度O(单词地长度之和)。
(三)具体代码:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int sigma_size=26;
const int maxnode=1e6+10;
char str[maxnode];
struct Trie{
    int ch[maxnode][sigma_size];
    int val[maxnode],sz,ans;
    vector<int>G[maxnode];
    queue<int>Q;
    void CLR(){
        for(int i=0;i<=sz;i++)G[i].clear();
        sz=1;ans=1e8;
        while(!Q.empty())Q.pop();
        memset(val,-1,sizeof val);
        memset(ch[0],0,sizeof ch[0]);
    }
    int idx(char c){return c-'a';}
    void Insert(char *s){                                     //建树
        vector<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]);
                G[u].push_back(sz);                           //双向边
                G[sz].push_back(u);
                if(i<n-2)V.push_back(sz);
                ch[u][c]=sz++;
            }
            u=ch[u][c];
        }
        for(int i=0;i<V.size();i++)G[V[i]].push_back(u);      //单向边
        V.clear();
    }
    int Query(char *s){                                       //查询 
        int u=0,n=strlen(s);
        ans=1e8;
        for(int i=0;i<n;i++){
            int c=idx(s[i]);
            if(!ch[u][c])break;
            u=ch[u][c];
            ans=min(ans,val[u]+n-i-1);
        }
        return min(ans,n);
    }
    void BFS(){                                               //求到达各个节点的最小操作数
        Q.push(0);val[0]=0;
        while(!Q.empty()){
            int u=Q.front();Q.pop();
            for(int i=0;i<G[u].size();i++){
                if(val[G[u][i]]==-1){
                    int v=G[u][i];
                    val[v]=val[u]+1;
                    Q.push(v);
                }
            }
        }
    }
}trie;
int main(){
    freopen("in.txt","r",stdin);
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        trie.CLR();
        for(int i=0;i<n;i++){
            scanf("%s",str);
            trie.Insert(str);
        }
        trie.BFS();
        for(int i=0;i<m;i++){
            scanf("%s",str);
            printf("%d\n",trie.Query(str));
        }
        printf("\n");
    }
    return 0;
}



猜你喜欢

转载自blog.csdn.net/xbb224007/article/details/79843939
You