1819: [JSOI]Word Query电子字典

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的单词的个数。
Sample Input

4 3

abcd

abcde

aabc

abced

abcd

abc

abcdd
Sample Output

-1

2

3

HINT

abcd在单词表中出现过;abc与单词abcd、aabc的编辑距离都是1;abcdd与单词abcd、abcde、abced的编辑距离都是1。

题解

就无脑的建个字典树
然后随便跑一下就好了。。
时间的话,我们可以吧一个询问看做多个不同的字符串
大概是60个不同的?
然后最差就是120*M
但考虑到n也不是特别大。。
实际上不会有这么差
于是就A了。。还跑得飞快

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=10005;
int son[N*21][26],num;
bool c[N*21];
int n,m;
char ss[25];
int len;
void Ins ()
{
    int now=0;len=strlen(ss);
    for (int u=0;u<len;u++)
    {
        int tt=ss[u]-'a';
        if (son[now][tt]==0)    son[now][tt]=++num;
    //  printf("%d %d %d\n",now,tt,son[now][tt]);
        now=son[now][tt];
    }
    c[now]=true;
}
int vis[N*21],cnt;//这个点访问过没 
int dfs (int now,int x,int y)
{
/*  printf("%d %d %d\n",now,x,y);
    system("pause");*/
    int sum=0;
    if (x>=len) 
    {
        if (y==0)
        {
            for (int u=0;u<26;u++)
            {
                if (son[now][u]==0) continue;
                sum=sum+dfs(son[now][u],x,y+1);//增加
            }
        }
        if (vis[now]!=cnt) sum=sum+c[now];
        vis[now]=cnt;
        return sum;
    }
    int tt=ss[x]-'a';
    if (son[now][tt]!=0) sum=sum+dfs(son[now][tt],x+1,y);
    if (y==0)
    {   
        sum=sum+dfs(now,x+1,y+1);//删除
        for (int u=0;u<26;u++)
        {
            if (son[now][u]==0) continue;
            sum=sum+dfs(son[now][u],x,y+1);//增加
            if (u!=tt) sum=sum+dfs(son[now][u],x+1,y+1);//替换 
        }
    }   
    return sum;
}
int solve ()
{
    int now=0;len=strlen(ss);
    bool tf=true;
    for (int u=0;u<len;u++)
    {
        int tt=ss[u]-'a';
        if (son[now][tt]==0) 
        {
            tf=false;
            break;
        }
        now=son[now][tt];
    }
    if (tf&&c[now]==true) return -1;
    cnt++;
    return dfs(0,0,0);
}
int main()
{
    memset(c,false,sizeof(c));
    num=0;
    scanf("%d%d",&n,&m);
    for (int u=1;u<=n;u++)
    {
        scanf("%s",ss);
        Ins();
    }
    cnt=0;memset(vis,false,sizeof(vis));
    for (int u=1;u<=m;u++)
    {
        scanf("%s",ss);
        printf("%d\n",solve());
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值