UVA 12526 Cellphone Typing (字典树)

博客详细介绍了如何使用字典树解决UVA 12526 Cellphone Typing问题。文章首先解释了题意,即根据用户输入的字母,系统会自动补全所有可能的单词前缀,直到完成一个单词。然后,博主分析了题目要求计算输入单词所需次数的期望,并指出这个期望等于字典中所有单词在字典树中经过的分叉数的总和除以单词总数。最后,博客提供了实现这一算法的代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

UVA 12526 Cellphone Typing (字典树)

tags: acm


模板题,虽然之前没去学,但是还是在比赛的时候现学现卖搞定了,算是我写的第一道字典树吧.

题意:

给你一个字典,包含许多单词.每当你按一个键时,系统会将其补全为所有以当前内容为前缀的单词的公共前缀.
如第一个样例,字典中的词为”hell”,”hello”,”heaven”,”goodbye”四个单词.
当你输入’h’时,系统将为你补全为”hell”,”hello”及”heaven”的公共前缀”he”,再输入’l’,继续补全为”hell”从而完成了”hell”的输入,你按了两次键(‘h’和’l’).
求输入字典中的单词所需要的次数的期望.

解析:

因为每次输入都会使得当前输入接近目标单词,因此这道题相当于统计字典中的单词在字典树中经过的的分叉数(每个分叉需要通过输入来确定到底是哪个单词),求和后除以单词书就能得到所求的期望,需要注意的是单词结尾也算是一个分叉.

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>

#define MAXN    1000000+10000

using namespace std;

const int sigma_size = 27;
const int maxnode = 1000000 + 10000;

struct Trie
{
    int ch[maxnode][sigma_size];
    int val[maxnode];
    int sz;
    Trie() { sz = 1; memset(ch[0], 0, sizeof(ch[0]));memset(val, 0, sizeof(val));}
    int idx(char c) { return c - 'a'; }

    void insert(char * s, 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]));
                val[sz] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = v;
    }

    int query(char *s)
    {
        int ret = 0;
        int len = strlen(s);
        int pos = 0;
        for (int i = 0; i < len; i++)
        {
            int cnt = 0;
            for (int j = 0; j < sigma_size; j++)
            {
                if (ch[pos][j] != 0)
                    cnt++;
            }
            if (val[pos])
                cnt++;
            if (cnt > 1||i==0)
            {
                ret++;
            }
            pos = ch[pos][idx(s[i])];
        }
        return ret;
    }
    void init()
    {
        sz = 1; memset(ch[0], 0, sizeof(ch[0])); memset(val, 0, sizeof(val));
    }
}dict;

char str[MAXN][100];

int main()
{
    int N;
    while (~scanf("%d", &N))
    {
        dict.init();
        for (int i = 0; i < N;i++)
        {
            scanf("%s",str[i]);
            dict.insert(str[i], 1);
        }
        int SUM = 0;
        for (int i = 0; i < N; i++)
        {
            int cnt = dict.query(str[i]);
            SUM += cnt;
        }
        printf("%.2lf\n", (SUM*1.0) / N);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值