题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1247
题目大意:给你一堆单词,找出其中的hat’s words. hat’s words定义为存在两个单词,恰好可以拼接成这个单词
思路:先构建一棵字典树,来存储每一个单词,然后构建一棵反串字典树。检查每一个单词,在两棵字典树中是否有两个单词可以拼成它
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e6;
struct Node{ //字典树结点
Node *s[26];
bool match;
};
int es[20];
int f[20];
struct Trietree{ //字典树
Node a[maxn];
int p;
Node *root;
Node *newNode(){ //新建结点
memset(a[p].s, 0, sizeof(a[p].s));
a[p].match = false;
return &a[p++];
}
Trietree(){ //初始化字典树
p = 0;
root = newNode();
}
void insert(char *s) //在字典树中插入字符串s
{
Node*cur = root;
while(*s != '\0'){
int t = *(s++) - 'a';
if(cur -> s[t] == NULL) cur -> s[t] = newNode();
cur = cur->s[t];
}
cur -> match = true;
}
void check(char *s) //查询s的所有前缀是否已出现过,记录在f中
{
int l = 0;
Node *cur = root;
while(*s != '\0'){
int t = *(s++) - 'a';
if(cur -> s[t] == NULL) return;
cur = cur->s[t];
l++;
if(cur->match) f[l] = 1;
}
}
};
Trietree a, b;
char s1[20], s2[20];
int ls;
void gets2()
{
ls = strlen(s1);
for(int i = 0; i < ls; i++){ //计算s1的反串s2
s2[i] = s1[ls-i-1];
}
s2[ls] = '\0';
}
bool checks() //查询是否能由两个串组成
{
memset(f, 0, sizeof(f));
b.check(s2);
for(int i = 1; i < ls; i++){
if(es[i] && f[ls-i]) return true;
}
return false;
}
void dfs(Node *from, int i) //查询每一个字符串
if(from->match){
s1[i] = '\0';
gets2();
if(checks()){
printf("%s\n", s1);
}
es[i] = true;
}
for(int j = 0; j < 26; j++){
if(from->s[j]){
s1[i] = j+'a';
dfs(from->s[j], i+1);
}
}
es[i] = 0;
}
int main()
{
int i;
while(scanf("%s", s1) != EOF){
gets2();
a.insert(s1);
b.insert(s2);
}
dfs(a.root, 0);
return 0;
}