uva 1401 - Remember the Word(字典树)

来源:互联网 发布:apache ip访问 编辑:程序博客网 时间:2024/05/21 05:21

题意:给一个长串(长度1~300000),s(1~4000)个单词,问长串可以完全分解成单词的方案种数?

解析:先保存单词前缀,然后将长串严格从左往右枚举以i位置为首的前缀数,注意剪枝(不重复),一次搜索后的结尾位置的后一个位置作为下次搜索的起始位置(进入优先队列,保证严格从左往右搜索)dp【i】表示以i位置为结尾的方案数,则dp【i】+=dp【w-1】;w为本次搜索的初始位置,一次循环就可以得到答案,

#include<iostream>#include<cstdio>#include<string.h>#include<functional>#include<queue>#include<vector>#include<algorithm>using namespace std;#define N 300005#define mod 20071027typedef long long LL;char s[N];int n,len,dp[N],vis[N],res;priority_queue<int, vector<int>, greater<int>  > sea;struct node{    int prefix;    bool isword;    node *next[27];    node()    {        prefix=0;        isword=false;        memset(next,NULL,sizeof(next));    }} *root;void insert(char *a){    node *p=root;    for(int i=0; a[i]; i++)    {        int x=a[i]-'a';        if(p->next[x]==NULL)  p->next[x]=new node;        p=p->next[x];    }    p->isword=true;    p->prefix++;}void search(int w){    node *p=root;    // if(w==len) {  res++; if(res>mod) res=res-mod; return;  }    for(int i=w; i<len; i++)    {        int x=s[i]-'a';        if(p->next[x]==NULL) break;        p=p->next[x];        if(p->isword)        {            dp[i]+=dp[w-1];             if(dp[i] >= 20071027) dp[i] %= 20071027;            if(!vis[i+1])            {                vis[i+1]=1;                sea.push(i+1);            }        }    }    while(!sea.empty())    {        int t=sea.top();//优先队列保证严格从左往右搜索        sea.pop();        search(t);    }}int main(){    int i,j,t=1;    char a[105];    while(~scanf("%s",s+1))    {        scanf("%d",&n);        s[0]='!';        res=0;        len=strlen(s);        root=new node;        for(i=0; i<n; i++)        {            scanf("%s",&a);            insert(a);        }        memset(dp,0,sizeof(dp));        memset(vis,0,sizeof(vis));        dp[0]=1;        vis[1]=1;        search(1);        printf("Case %d: %d\n",t++,dp[len-1]%mod);        free(root);    }    return 0;}


原创粉丝点击