题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1247
题目大意:
给出一些单词,以EOF结束,看其中哪一个单词可以由其他两个单词组成,将其输出
解题思路:
将所有单词存入字典树中,每个单词拆成两部分查询是不是字典树中的单词。
此处是查询是不是单词,需要加单词标记数组,在每个单词最后一位的末尾那个节点标记true
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<map>
#include<set>
#include<cmath>
#include<algorithm>
#include<vector>
#include<sstream>
#define lowbot(i) (i&(-i))
using namespace std; const int maxn = 1e6 + ;
int tree[maxn][];
//字典树tree[u][v]表示编号为u的节点的下一个字母为v连接的节点的编号
int idx(char c){ return c - 'a'; }//可以写成宏定义
int tot = ;//根节点编号为1
bool is_word[maxn];//单词结束标记
void Insert(char s[], int u)//u表示根节点
//插入字符串s
{
for(int i = ; s[i]; i++)
{
int c = idx(s[i]);
if(!tree[u][c])
tree[u][c] = ++tot;
u = tree[u][c];
}
is_word [u] = true; //查询单词的时候需要标记最后一个节点的地方是单词
} bool Find(char s[], int u)
//查询s是否是前缀
{
for(int i = ; s[i]; i++)
{
int c = idx(s[i]);
if(!tree[u][c])
return false;
u = tree[u][c];
}
//return true;
return is_word[u]; //查询单词的时候,需要返回当前是不是单词结束标志
}
char s[][], s1[];
int main()
{
int n = ;
while(scanf("%s", s[n]) != EOF)Insert(s[n++], ); for(int i = ; i < n; i++)
{
for(int j = ; s[i][j]; j++)//从下标1开始,从0开始的话s1就变成空串了
{
memcpy(s1, s[i], sizeof(s[i]));
s1[j] = ;
//分割成两个字符串: s1和(s[i] + j)
//cout<<s1<<" "<<(s[i] + j)<<endl;
if(Find(s1, ) && Find(s[i] + j, ))
{
cout<<s[i]<<endl;
break;
}
}
}
return ;
}