51nod 1526 分配笔名(字典树)

1526 分配笔名

题目来源: CodeForces

基准时间限制:1 秒 空间限制:131072 KB 分值: 320 难度:7级算法题

 收藏

 关注

班里有n个同学。老师为他们选了n个笔名。现在要把这些笔名分配给每一个同学,每一个同学分配到一个笔名,每一个笔名必须分配给某个同学。现在定义笔名和真名之间的相关度是他们之间的最长公共前缀。设笔名为a,真名为b,则他们之间的相关度为lcp(a,b)。那么我们就可以得到匹配的质量是每一个同学笔名和真名之间相关度的和。

现在要求分配笔名,使得匹配质量最大。

样例解释:

·        bill → bilbo (lcp = 3)

·        galya → galadriel (lcp = 3)

·        gennady → gendalf (lcp = 3)

·        toshik → torin (lcp = 2)

·        boris → smaug (lcp = 0)

Input

单组测试数据。 第一行有一个整数n (1≤n≤100000),表示班级中同学的数目。 接下来n行,表示每一个同学的真名,每一个名字是非空串,且由小写字母组成。 名字可能重复。 最后n行是老师已经安排好的笔名。每一个笔名是一个非空串,且由小写字母组成。 笔名可能重复。 输入的字符总数目不超过 800000。

Output

输出最大的匹配质量。
Input示例
样例输入1
5
gennady
galya
boris
bill
toshik
bilbo
torin
gendalf
smaug
galadriel

Output示例

样例输出1
11

解:这题的思路有点吊,直接用模式串去匹配文本串就可以了,因为假设一个不是最优的模式串匹配了文本串后 进行删除操作,然后最优的模式串匹配这个文本串时

减少的前缀匹配数量 实际上由以前匹配过的模式串提前加上了 。。。这个思路有点吊 

代码:

#include<iostream>
#include<stdio.h>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=800005;

int a[maxn][26];
int b[maxn];
char str[1000];
int size = 0;
int ans = 0;

void init(){
    size = 0;
    ans = 0;
    memset(b,0,sizeof(b));
    memset(a,0,sizeof(a));
}
void insert(){
    int len = strlen(str);
    int root = 0;
    for (int i = 0; i < len; ++i){
        int index = str[i] - 'a';
        if(!a[root][index])
            a[root][index] = ++size;
        root = a[root][index];
        b[root]++;
    }   
}

void check(){
    int len = strlen(str);
    int root = 0;
    for (int i = 0; i < len; ++i){
        int index = str[i] - 'a';
        if(!a[root][index])
            break;
        root = a[root][index];
        if(b[root])
            ans++, b[root]--;
    }   
}

int main(int argc, char const *argv[]){
    int n;
    scanf("%d",&n);
    for (int i = 0; i < n; ++i){
        scanf("%s",str);
        insert();
    }
    for (int i = 0; i < n; ++i){
         scanf("%s",str);
         check();
    }
    printf("%d\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值