Uva1401 Trie树 + 简单dp

题意 给你m个短字符串和一个长串,问你长串拆分成由短串组成的方法数。

思路 dp[i] 表示从i开始的长串后缀,可以用短串组成的方案数。dp[i] += dp[i+len(x)]  其中x是从i开始的长串后缀的前缀,这个前缀属于短串集合。初始条件dp[n] = 1.

           用短串建立Trie树,用长串后缀去在字典树上匹配,找到满足条件的短串,更新dp


注意:Trie树的maxnode要开够!!被这个点WA死了….


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <assert.h>
using namespace std;
const int maxn = 310005;
const int MOD = 20071027;

const int maxlen = 110;
const int maxnum = 4000;
const int sigmasize = 26;
const int maxnode = maxnum*maxlen;
struct Trie{
	//内容存的是节点i,遇到j字符时,前往的节点号 
	int ch[maxnode][sigmasize];
	int val[maxnode];
	int sz;
	char ji;
	void init(char j = 'a'){
		ji = j;
		sz = 1;
		memset(ch[0],0,sizeof(ch[0]));
	}
	int idx(char c){
		return c - ji;
	}
	//插入一个单词 
	void insert(char* s,int v)
	{
		assert(v != 0);
		int now = 0;
		int n = strlen(s);
		for(int i=0;i<n;i++)
		{
			int c = idx(s[i]);
			if(!ch[now][c]){
				memset(ch[sz],0,sizeof(ch[sz]));
				val[sz] = 0;
				ch[now][c] = sz++;
			}
			now = ch[now][c];
		}
		val[now] = v;
	}
	//查找一个单词是否在字典树中,在返回val,不在,返回0 
	int find(char* str)
	{
		int now = 0;
		while(*str != 0)
		{
			int p = idx(*str);
			if(!ch[now][p])
			{
				return 0;
			}
			now = ch[now][p];
			str++;
		}
		return val[now];
	}
};
Trie tree;

int dp[maxn];
char str[maxn];
int n,m;
char tmp[maxlen];

int main()
{
	int i,j,t;
	t = 0;
	while(scanf("%s",str) != EOF)
	{
		t++;
		tree.init();
		n = strlen(str);
		scanf("%d",&m);
		
		for(i=0;i<m;i++)
		{
			scanf("%s",tmp);
			tree.insert(tmp,/*strlen(tmp)*/1);
		}
		memset(dp,0,sizeof(dp));
		dp[n] = 1;
		for(i=n-1;i>=0;i--)
		{
			int now = 0;
			for(j=0;i+j<n;j++)
			{
				int c = tree.idx(str[i+j]);
				if(!tree.ch[now][c]){
					break;
				}
				now = tree.ch[now][c];
				if(tree.val[now] != 0)
				{
					dp[i] = (dp[i] + dp[i+j+1]) % MOD;
				}
			} 
		}
		cout<<"Case "<<t<<": "<<dp[0]<<endl; 
	}
	return 0;
}
    原文作者:Trie树
    原文地址: https://blog.csdn.net/luke2834/article/details/44888753
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞