题目大意:在一个字典中,找出可以这样一个单词,这个单词可以由字典里的任意两个单词连接而来,而且只能是两个。
解题思路:建立一颗字典树,标记字典树的每个节点是否是一个单词的结尾,然后在字典树上查找字典里面的每一个单词,如果这个单词的中间的节点是某个单词的结尾的话,就去查找这个单词剩下的一部分,由于输入已经保证的字典序,所以按照输入的顺序去检查就可以按照字典序输出了。
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 120020
#define maxnode 50000
using namespace std;
char dic[maxn][50];
int ic=0;//字典长度
int slen[maxn];//字典中每个单词的长度
struct TrieStruct
{
//字典树相关
int pos;
int sz[maxnode][26];//the tree node
bool val[maxnode]; //idicate the node if the words end
int idx(char c)
{
return c-'a';
}
TrieStruct()
{
pos=0;
memset(val,0,sizeof(val));
memset(sz[0],0,sizeof(sz[0]));
}
void insert(char *s)
{
int len=strlen(s);
slen[ic]=len;
int ch,ix=0;
for(int i=0;i<len;i++)
{
ch=idx(s[i]);
if(sz[ix][ch])
{
ix=sz[ix][ch];
}
else
{
pos++;
sz[ix][ch]=pos;
memset(sz[pos],0,sizeof(sz[pos]));
ix=pos;
}
}
val[ix]=1;
}
bool find(char *s)
{
int len=strlen(s);
int ix=0;
int c=0;
for(int i=0;i<len;i++)
{
c=sz[ix][idx(s[i])];
if(!c)
{
return false;
}
else
{
ix=c;
}
}
return val[c];
}
bool check(char *s,int len)
{
int c;
int ix=0;
for(int i=0;i<len;i++)
{
c=sz[ix][idx(s[i])];
if(!c)return false;
else
{
if(val[c]&&i!=len-1)
{
if(find(s+i+1))return true;
}
ix=c;
}
}
return false;
}
}myTrie;
void solve()
{
for(int i=0;i<ic;i++)
{
if(myTrie.check(dic[i],slen[i]))
{
printf("%s\n",dic[i]);
}
}
}
int main()
{
while(scanf("%s",dic[ic])!=EOF)
{
myTrie.insert(dic[ic]);
ic++;
}
solve();
return 0;
}