刷题总结——分配笔名(51nod1526 trie树)

题目:

班里有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


题解:

  这道题一来没有注意到一一对应关系直接上trie树暴力匹配挂成0······

  下次一定要仔细读题了···其实保证两次笔名的一一对应关系的方法是很简单的··具体看代码

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
#include<ctime>
using namespace std;
const int N=800005;
int n,son[N][26],len,tot,a[N],b[N];
char s[N];
inline void build(int a[])
{
  int po=0;
  for(int i=1;i<=len;i++)
  {
    if(!son[po][s[i]-'a'])  son[po][s[i]-'a']=++tot;
    po=son[po][s[i]-'a'];a[po]++;
  }
}
int main()
{
  //freopen("a.in","r",stdin);
  scanf("%d",&n);
  for(int i=1;i<=n;i++)
  {
    scanf("%s",s+1);len=strlen(s+1);build(a);
  }
  for(int i=1;i<=n;i++)
  {
    scanf("%s",s+1);len=strlen(s+1);build(b);
  }
  int ans=0;
  for(int i=1;i<=tot;i++)  ans+=min(a[i],b[i]);
  cout<<ans<<endl;
  return 0;
}



原文地址:https://www.cnblogs.com/AseanA/p/7718604.html