#define MAX_WORD_CNT 4000
#define MAX_WORD_LEN 100
#define MAX_STRING_LEN 300000
int d[MAX_STRING_LEN];
typedef struct Trie
{
//生成字典树
#define MAX_NODE 100
#define MOD 20071027
int nodes[MAX_NODE][26];//第i个结点的第j个孩子 的节点编号;
int sz;//节点的总数
int value[MAX_NODE];//节点权重,可以标注是否为单词的结尾
//value[0] 没有意义
Trie()
{
sz = 1;
memset(nodes[0], 0, sizeof(nodes[0]));
memset(value, 0, sizeof(value));
}
int get_index(char a){ return a - 'a'; }
void insert(char* content, int weight)//插入字符串content
{
//节点总数从1开始.
//
int u = 0;//根节点从0开始
int v = 0;
int len = strlen(content);
assert(len <= MAX_STRING_LEN);
//memset(nodes, 0, sizeof(nodes));//错,如果再插入一个字符串,之前的nodes的编号信息全部丢失
for (v = 0; v < len; v++)
{
char tmp = content[v];//遍历待插入字符串的各个字符
int idx = tmp - 'a';//对应的编号
if (!nodes[u][idx])//表示新节点
{//刚开始是0,根节点,新插入的节点'a'不存在
//memset(nodes[u], 0, sizeof(nodes[u]));//错,此处应该是第sz个节点,连接的信息都重置化
memset(nodes[sz], 0, sizeof(nodes[sz]));//即将插入的第sz个节点
value[sz] = 0;
nodes[u][idx] = sz;//当前插入的是第几个节点,或者说是节点编号
sz++;//新添加的节点
//u = nodes[u][idx];//指向的下一个节点 编号 错,如果这个节点存在呢,所以放的位置不对
}
u = nodes[u][idx];
}
value[u] = weight;
}
int find(const char* match)
{
int u = 0;
int flag = 1;
int len = strlen(match);
for (int i = 0; i < len; i++)
{
int idx = get_index(match[i]);
if (nodes[u][idx])
{
u = nodes[u][idx];//逐个字符去找
}
else
{
flag = 0;
break;
}
}
if (!value[u])//不要忘记了,是否为某个单词的结尾
flag = 0;
return flag;
}
void query(char* s, int state)
{
int u = 0;
int n = strlen(s);
//"d"
//"cd"
//"bcd"
//"abcd"
int len = 0;
for (int i = state; i < n; i++)//匹配是否存在匹配S[i...L]的前缀,
{
char c = s[i];//遍历s的字符,从state位置开始
int idx = get_index(c);//该字符对应的child编号
if (!nodes[u][idx])//如果不存在该字符,则返回
return;
//如果存在,则指向下一个编号
u = nodes[u][idx];
len++;//len(x)
if (value[u] && u)//是否该编号节点 为某个单词的结尾
d[state] = (d[state] + d[state + len]) % MOD;
}
}
}Trie;
//单词拆分
//词典集合
//文本串
//将文本串拆分 为词典的多个单词拼接,单词可以重复使用
//Trie树
//Trie的精髓在于利用了公共前缀,生成一个关系树,一条边代表一个字符,节点的val值来记录是否为单词结尾;
//Trie test;
//test.insert("abcdefg", 1);
//test.insert("abab", 1);
//test.insert("tede", 1);
//test.insert("tea", 1);
////find "teacher"
//string sample("teacher");
//cout << sample << ":" << test.find(sample.c_str()) << endl;
////find "ted"
//sample = "ted";
//cout << sample << ":" << test.find(sample.c_str()) << endl;
//单词拆分
//eg
Trie test;
test.insert("a", 1);
test.insert("b", 1);
test.insert("ab", 1);
test.insert("cd", 1);
test.insert("abcd", 1);
//文本串 abcd
//d[i] 表示以第i个字符开始的后缀,即 S[i...L]的分解方案数
//d[0] 后缀S[0...L] "abcd" 字典单词匹配 "a", "ab" d[0] = d[0+1] + d[0+2] = 2
//d[1] 后缀S[1...L] "bcd" "b", d[1] = d[1+1] = 1
//d[2] 后缀S[2...L] "cd" "cd" d[2] = d[2+2] = 1
//d[3] 后缀S[3...L] "d" 无
//d[4] = 1
//DP动态规划 d[3] ->d[2] ->d[1] ->d[0]
//串 "abcd"
char s[MAX_STRING_LEN] = { "abcd" };
int n = strlen(s);
memset(d, 0, sizeof(d));
d[n] = 1;//结尾
for (int i = n - 1; i >= 0; i--)//从文本字符串最后一个元素开始
{
test.query( s, i);
}
cout << "d[0]=" << d[0] << endl;