UVA 11732 链式字典树

来源:互联网 发布:松下plc编程手册 编辑:程序博客网 时间:2024/05/21 10:16

题意

给一些字符串,问如果使用strcmp函数对这些字符串两两比较,需要进行多少次字符比较。(strcmp函数在题目中已给出,如果字符相等,则还需要将该字符与’\0’进行比较)

题解

链式字典树我自己的叫法,网上大多数题解都把这种字典树叫做左儿子,右兄弟的字典树,但是这种叫法感觉会引起误解。一开始我以为右兄弟是根的兄弟,后来才意识到右兄弟是左儿子的兄弟。
具体效果见下图。
链式字典树
可以看到,这样存储只需要开节点个数大小的数组就可以了,不需要再开一个二维数组,从而节省了大量空间。对于这道题来说,所需的数组空间直接降了1.5个数量级,效果是非常明显的。
至于链式字典树的存储方式,可以用链表,也可以用数组模拟链表。这里我选择用数组模拟链表来避免指针操作。

v=sz++;c[v]=st[i];val[v]=0;son[v]=0;nex[v]=son[u];son[u]=v;

上述代码是链式字典树增加节点的过程,由于链式字典树本身的数组无法记录节点对应的字符信息,所以需要增加一个字符记录数组,也就是C。val用来记录节点值,在本题中用来记录访问次数。nex对应上图中的next,son对应上图中的son1。
通过链式字典树解决了存储空间的问题以后,本题就算解决一半了。另一半是统计比较次数。对于普通字符(除了’\0’以外),每次字符比较都会比较两次,调用字符比较的次数就是val[u]值(u表示将字符串插入字典树过程中访问的节点)。如果一直比较到结尾还没有分出大小,那么还会额外针对’\0’比较两次,这时候就需要+cnt[u]。(u代表末尾节点)如果在比较过程中分出了大小,还需要再加1次,因为最后一次不相等的比较没有计算。
最后将所有计算得到的值累加起来就是所求的总比较次数。

代码

#include <iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#include<cmath>#include<queue>#include<string>#include<set>#include<map>#include<bitset>#include<stack>#include<string>#define UP(i,l,h) for(int i=l;i<h;i++)#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)#define W(a) while(a)#define MEM(a,b) memset(a,b,sizeof(a))#define LL long long#define INF 0x3f3f3f3f#define MAXN 100010#define MOD 1000000009#define EPS 1e-10using namespace std;int ch[4000010];int val[4000010],nex[4000010],son[4000010],cnt[4000010];char c[4000010];char st[1010];int sz;LL ans;int getNum(char c) {    if(c>='0'&&c<='9') {        return c-'0';    } else if(c>='a'&&c<='z') {        return c-'a'+10;    } else if(c>='A'&&c<='Z') {        return c-'A'+36;    }}void insert() {    int u=0;    int len=strlen(st);    ans+=val[0];    val[0]++;    UP(i,0,len) {        int v;        for(v=son[u];v!=0;v=nex[v]){            if(c[v]==st[i]){                break;            }        }        if(!v) {            v=sz++;            c[v]=st[i];            val[v]=0;            son[v]=0;            nex[v]=son[u];            son[u]=v;        }        u=v;        ans+=val[u]*2;        val[u]++;    }    if(cnt[u]){        ans+=cnt[u];    }    cnt[u]++;}int main() {    int n;    int ks=1;    W(~scanf("%d",&n)) {        if(n==0)            break;        MEM(ch,0);        MEM(val,0);        MEM(nex,0);        MEM(son,0);        MEM(cnt,0);        MEM(c,0);        ans=0;        sz=1;        UP(i,0,n) {            scanf("%s",st);            insert();        }        printf("Case %d: %lld\n",ks++,ans);    }}/*3abcabcabc*/
原创粉丝点击