UVA 1401 Remember the Word(DP+字典树Trie)

UVA 1401 Remember the Word(DP+字典树Trie)

题意:

        给你一个由N个单词组成的词典,和一个字符串S。问你S由N中的单词组成的方法有多少种?字典中的单词可以重复使用但是不可重叠。

分析:

        我们令d[i]=x表示S串的后缀[i,L-1]串有多少种构成方式(注意:如果令d[i]=x表示S串的前缀串[0,i]有多少种构成方式的话,就不能用字典树来查找单词了)。其中L=strlen(S),字符从0到L-1下标。

        那么d[i]=sum(  d[i+len(x)]  ) 仅当[i,i+len(x)-1]区间的字符正好是字典中的一个单词时.(想想是不是?)

        然后初值d[L]=1,其他所有d值初始为0,然后从L-1一直递推到0,最终结果就是d[0].

当我们递推d[i]的时候,我们先用串[i,L-1]去查询字典树,如果查询到了一个长5的单词,那说明d[i] += d[i+5],如果查询到另一个长8的单词,那说明d[i] +=d[i+8].

        另外要说明的是:字典树中的v值保存的是该节点单词的长度,如果该节点不是单词,那么v=0.

AC代码:

#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
#define MAX 26
const int maxnode=4000*100+100;
const int sigma_size=26;

struct Trie
{
    int ch[maxnode][sigma_size];
    int val[maxnode];
    int sz;
    void clear()
    {
        sz=1;
        memset(ch,0,sizeof(ch));//ch值为0表示没有儿子
    }
    int idx(char c)
    {
        return c-'a';
    }
    void insert(char *s)
    {
        int u=0,n=strlen(s);
        for(int i=0;i<n;i++)
        {
            int id=idx(s[i]);
            if(ch[u][id]==0)//无该儿子
            {
                ch[u][id]=sz;
                memset(ch[sz],0,sizeof(ch[sz]));
                val[sz++]=0;
            }
            u=ch[u][id];
        }
        val[u]=n;
    }
    void find(char *s,int len,vector<int> &vc)
    {
        int u=0;
        for(int i=0;i<len;i++)
        {
            int id=idx(s[i]);
            if(ch[u][id]==0)
                return;
            u=ch[u][id];
            if(val[u]) vc.push_back(val[u]);
        }
    }
};

Trie trie;
const int MAXN=300000+1000;
const int MOD = 20071027;
int d[MAXN];
char S[MAXN],word[1000];
int main()
{
    int kase=1;
    while(scanf("%s",S)==1)
    {
        int w;
        scanf("%d",&w);
        trie.clear();
        for(int i=0;i<w;i++)
        {
            scanf("%s",word);
            trie.insert(word);
        }
        memset(d,0,sizeof(d));
        int L=strlen(S);
        d[L]=1;
        for(int i=L-1;i>=0;i--)
        {
            vector<int> vc;
            trie.find(S+i,L-i,vc);
            for(int j=0;j<vc.size();j++)
                d[i]=(d[i]+d[i+vc[j]])%MOD;
        }
        printf("Case %d: %d\n", kase++, d[0]);
    }
    return 0;
}

你可能感兴趣的:(ACM)