Uva - 12506 - Shortest Names(Trip)

题意:有n个由小写字母组成的名字,任何一个名字都不是另一个名字的前缀,对于每个名字,只取它的最短前缀,使得这n个取出来的前缀互不相同,问这些前缀的总字母个数(1 <= n <= 1000, 所有名字的总长度不超过1000000,测试数据级数T <= 10)。

题目链接:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3950

——>>看完题,想着这会不会是前缀树的题目,又看到名字长度不超过1000000,26^1000000个结点?于是不再考虑Trip。。。赛后才发现,看错题目了,1000000是所有名字加起来的最大总字母个数,正正是用Trip的题目。

设cnt[i]为第i个结点有多少个名字经过,那么,若cnt[i]为1,则表明只有1个名字经过,下面只表示1个人,于是可以停止往下的扫描;若cnt[i] > 1,则表明不止1个名字经过,必须往下扫描,直到能分辨出来为止。

Trip的数组写法:

#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

const int maxnode = 1000000 + 10;
const int maxn = 1000 + 10;
char name[maxn];
int n, ch[maxnode][26];
int cnt[maxnode];

struct Trip{
    int sz;
    Trip(){
        sz = 1;
        memset(ch[0], 0, sizeof(ch[0]));
        memset(cnt, 0, sizeof(cnt));
    }

    int idx(char c){
        return c - 'a';
    }

    void insert(char *s){
        int len = strlen(s), u = 0, i;
        for(i = 0; i < len; i++){
            int c = idx(s[i]);
            if(!ch[u][c]){
                memset(ch[sz], 0, sizeof(ch[sz]));
                ch[u][c] = sz++;
            }
            cnt[ch[u][c]]++;
            u = ch[u][c];
        }
    }

    void solve(){
        int ret = 0, i, u;
        queue<int> qu;
        qu.push(0);
        while(!qu.empty()){
            u = qu.front(); qu.pop();
            for(i = 0; i < 26; i++) if(ch[u][i]){
                ret += cnt[ch[u][i]];
                if(cnt[ch[u][i]] > 1) qu.push(ch[u][i]);
            }
        }
        printf("%d\n", ret);
    }
};

int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        Trip trip;
        scanf("%d", &n);
        for(int i = 0; i < n; i++){
            scanf("%s", name);
            trip.insert(name);
        }
        trip.solve();
    }
    return 0;
}

Trip的指针写法(事先不用预定空间,比较灵活):

#include <cstdio>
#include <cstring>
#include <queue>

using namespace std;

const int maxn = 1000 + 10;
char name[maxn];
int n;

struct node{
    int cnt;
    node *next[26];
    node(){
        cnt = 0;
        memset(next, 0, sizeof(next));
    }
};

struct Trip{
    node *root;

    Trip(){
        root = new node;
    }

    int idx(char c){
        return c - 'a';
    }

    void insert(char *s){
        int len = strlen(s), i;
        node *t = root;
        for(i = 0; i < len; i++){
            int c = idx(s[i]);
            if(!t->next[c]) t->next[c] = new node;
            t->next[c]->cnt++;
            t = t->next[c];
        }
    }

    void solve(){
        int ret = 0, i;
        node *t = new node;
        queue<node*> qu;
        qu.push(root);
        while(!qu.empty()){
            t = qu.front(); qu.pop();
            for(i = 0; i < 26; i++) if(t->next[i]){
                ret += t->next[i]->cnt;
                if(t->next[i]->cnt > 1) qu.push(t->next[i]);
            }
        }
        printf("%d\n", ret);
    }
};

int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        Trip trip;
        scanf("%d", &n);
        for(int i = 0; i < n; i++){
            scanf("%s", name);
            trip.insert(name);
        }
        trip.solve();
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值