您的位置:首页 > 其它

soj 3596 Article Decryption(trie树 + dp)

2015-11-08 16:29 330 查看
@(K ACMer)

题意:

给你一些单词,和一个长字符串s,s是由这些单词组成的,总共有多少种组成的可能?

分析:

问有多少种可能显然的dp,很容易的想到定义dp[i]为s前i个字符形成的字符串最多有多少种可能,则有转移方程:dp[i]=∑j=0i−1isword(j+1,i) ? dp[j] : 0(注:其中isword(j+1,i)为判断s串j+1到i段是否为单词的函数)

这里在实现isword()的时候如果用map去查找,复杂度是O(n∗l),显然不好,就需要建一颗trie树,O(l)的去查是否为单词.

总的复杂度是(O(l∗n2+m∗l)),其中n为s的长度,m为单词的个数m∗l的复杂度是建立trie树的过程中产生的.

code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <string>
#include <queue>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
const int mod = 835672545, INF = 0x3fffffff, maxn = 1e5 + 40;
char str[maxn];
int dp[maxn];

#define  MAX 26

typedef struct trienode
{
int num;  // 该节点前缀 出现的次数
struct trienode *next[MAX]; //该节点的后续节点
} trienode;

trienode memory[100000]; //先分配好内存。 malloc 较为费时
int mcnt = 0; // 内存计数器

//初始化一个节点。nCount计数为1, next都为null
trienode* create(void)
{
trienode* tmp = &memory[mcnt++];  //节点指向一个已经分配好的内存节点之一.
tmp -> num = 0;  //当前节点初始化个数为1
for (int i = 0; i < MAX; i++)  //当前节点的所有儿子的指针初始化为null
tmp->next[i] = NULL;
return tmp;  //返回分配好的当前节点的指针
}

void insert(trienode* tmp, char* str)   //把字符串加入tire树中
{
int i = 0, k;
while (str[i]) {  //一个一个的插入字符
k = str[i++] - 'a'; //当前字符 应该插入的位置
if (tmp -> next[k] );  //如果当前节点的该儿子已经存在,就把儿子的频率加1
else
tmp -> next[k] = create();  //如果该节点的该儿子不存在,就创建一个
tmp = tmp -> next[k]; // 树往高深度进展
if (str[i] == '\0') tmp -> num++;
}
}

int search(trienode* root, char * str)  //查找str为前缀的字符串,在树中的个数
{
if (root == NULL)  //如果根节点为空,返回0
return 0;
trienode* tmp = root;  //当前节点
int i = 0, k;
while (str[i]) { //一直查找完整个字符串放可罢休
k = str[i++] - 'a';  //当前节点对应的儿子的位置
if (tmp -> next[k])  //如果儿子存在,就递归到儿子
tmp = tmp->next[k];
else
return 0;  //前缀已经查完了,退出
}
return tmp -> num; //返回最后的那个字符,所在节点的nCount(也就是这个字符串在原串中的数量)
}

bool judge(int i, int j, trienode* rt) {
char* p = str + i;
char c = str[j + 1];
str[j + 1] = '\0';
int ok = search(rt, p);
str[j + 1] = c;
return ok == 0 ? false : true;
}

int main(void)
{
int T;
scanf("%d", &T);
while (T--) {
trienode* rt = create();
int n;
scanf("%d", &n);
while (n--) {
scanf("%s", str);
insert(rt, str);
}
str[0] = 'a';
scanf("%s", str + 1);
int slen = strlen(str) - 1;
memset(dp, 0, sizeof(dp));
dp[0] = 1;
for (int i = 1; i <= slen; i++) {
for (int j = i - 1; j >= 0; j--) {
if (judge(j + 1, i, rt))
dp[i] = (dp[i] % mod + dp[j] % mod) % mod;
}
}
printf("%d\n", dp[slen]);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  dp