UVA-1401 - Remember the Word -----Trie前缀树

题意:给出N个不同单词和一个长字符串S。把这个字符串分解成若干个单词的连接(单词尅重复使用),问有多少种方法?


分析:令d[i]表示从字符i开始的字符串的分解方案数,则d[i]=sum{d[i+len[x]] | 单词x是S[i...len]的前缀};


详看《算法竞赛入门经典》---刘汝佳--Page 208..


#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<vector>
using namespace std;


#define sigma_size 26     
#define maxnode 400010    //节点个数
#define MOD 20071027

struct Trie//Trie模板
{
	int ch[maxnode][sigma_size];//maxnode表示节点个数,每个节点有26种情况,所以ch数组能表示所有情况
	int val[maxnode];           //存节点的信息
	int sz;                     //节点总个数
	void clear(){sz=1; memset(ch[0],0,sizeof(ch[0]));}//初始化
	int idx(char c){ return c - 'a'; }

	void insert(char *s, int v)
	{
		int u=0,n=strlen(s);
		for(int i=0;i<n;i++){
			int c=idx(s[i]);
			if(!ch[u][c]){ //节点不存在
				memset(ch[sz],0,sizeof(ch[sz]));
				val[sz]=0;
				ch[u][c]=sz++;
			}
			u=ch[u][c];//这样存就可以保证从每个节点,都能访问他的下一个节点了
		}
		val[u]=v;
	}

	void find(char *s,int len,vector<int>& ans)
	{
		int u=0;
		for(int i=0;i<len;i++)
		{
			
			int c=idx(s[i]);
			if(ch[u][c]){
				u=ch[u][c];
				if(val[u])
					ans.push_back(val[u]);
			}
			else
				break;
		}
	}
};


Trie node;

char sh[300010];
int d[4005];
int sum[300010];
int main()
{
	int i=0,j,k;
	int t=0;
	while(~scanf("%s",sh))
	{
		t++;
		int n;
		node.clear();
		char p[105];
		scanf("%d",&n);
		for(i=1;i<=n;i++){
			scanf("%s",p);
			node.insert(p,i);
			d[i]=strlen(p);
		}
		int len=strlen(sh);
		memset(sum,0,sizeof(sum));
		sum[len]=1;
		for(i=len-1;i>=0;i--){
			
			vector<int> ans;
			node.find(sh+i,len-i,ans);
			for(j=0;j<ans.size();j++)
			{
				sum[i]=(sum[i]+sum[i+d[ans[j]]])%MOD;
			}
		}
		printf("Case %d: %d\n",t,sum[0]);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值