一、HDU - 1247 Hat’s Words(字典树)
Problem Description
A hat’s word is a word in the dictionary that is the concatenation of exactly two other words in the dictionary.
You are to find all the hat’s words in a dictionary.
Input
Standard input consists of a number of lowercase words, one per line, in alphabetical order. There will be no more than 50,000 words.
Only one case.
Output
Your output should contain all the hat’s words, one per line, in alphabetical order.
Sample Input
a ahat hat hatword hziee word
Sample Output
ahat hatword
解题思路:模板题目
#include <bits/stdc++.h>
using namespace std;
//#define pb push_back
int tot;
int tre[50005][26];
bool vis[50005];
vector<string>v,ans;
int myInsert(string str,int rt)///插入单词
{
for(int j=0; j<str.size(); j++)///遍历单词string
{
int x=str[j]-'a';
if(tre[rt][x]==0)///新节点
tre[rt][x]=++tot;///节点编号
rt=tre[rt][x];///下一个节点
}
vis[rt]=true;///单词末尾标记
}
bool myfinds(string str,int rt)///查询
{
for(int i=0; i<str.size(); i++)
{
int x=str[i]-'a';
if(tre[rt][x]==0)return false;
rt=tre[rt][x];
}
return vis[rt];
}
int main()
{
tot=0;
int num=++tot;
memset(vis,false,sizeof(vis));
memset(tre[num],0,sizeof(tre[num]));
string a;
v.clear();
ans.clear();
// while(cin>>a)///建树
// insert(a,num),v.pb(a);
while(cin>>a){
if(a == "#")
{
break;
}
///建树
myInsert(a,num);
v.push_back(a);
}
for(int i=0; i<v.size(); i++)
{
for(int j=0; j<v[i].size(); j++)
{
string tma=v[i].substr(0,j+1);
string tmb=v[i].substr(j+1);
if(myfinds(tma,num)&&myfinds(tmb,num))
{
///一旦当前单词确定是ans,则可以不用再遍历这个单词剩余的组合
ans.push_back(v[i]);
break;
}
}
}
sort(ans.begin(),ans.end());
for(int i=0; i<ans.size(); i++) cout<<ans[i]<<"\n";
}
二、HDU - 1251 统计难题
Ignatius最近遇到一个难题,老师交给他很多单词(只有小写字母组成,不会有重复的单词出现),现在老师要他统计出以某个字符串为前缀的单词数量(单词本身也是自己的前缀).
Input
输入数据的第一部分是一张单词表,每行一个单词,单词的长度不超过10,它们代表的是老师交给Ignatius统计的单词,一个空行代表单词表的结束.第二部分是一连串的提问,每行一个提问,每个提问都是一个字符串.
注意:本题只有一组测试数据,处理到文件结束.
Output
对于每个提问,给出以该字符串为前缀的单词的数量.
Sample Input
banana band bee absolute acm ba b band abc
Sample Output
2 3 1 0
解题思路:Map直接干 也可以直接用字典树模板
#include <bits/stdc++.h>
using namespace std;
int main(){
char str[10];
map<string, int> m;
while(gets(str)){
int len = strlen(str);
if ( !len ) break; //输入了一个空行
for(int i = len; i>0; i--){
str[i]='\0'; //从后往前删除这个字符串的字符,得到前缀
m[str]++; //统计前缀的数量
}
}
while( gets(str) ) cout << m[str] << endl;
return 0;
}
#include <bits/stdc++.h>
using namespace std;
int trie[1000010][26]; //数组定义字典树,存储下一个字符的位置
int num[1000010]={0}; //以某一字符串为前缀的单词的数量
int pos = 1; //当前新分配的存储位置
void Insert(char str[]){ //在字典树中插入某个单词
int p = 0;
for(int i=0;str[i];i++){
int n = str[i]-'a';
if(trie[p][n]==0) //如果对应字符还没有值
trie[p][n] = pos++;
p = trie[p][n];
num[p]++;
}
}
int Find(char str[]){ //返回以某个字符串为前缀的单词的数量
int p = 0;
for(int i=0;str[i];i++){
int n = str[i]-'a';
if(trie[p][n]==0)
return 0;
p = trie[p][n];
}
return num[p];
}
int main(){
char str[11];
while(gets(str)){
if ( !strlen(str) ) break; //输入了一个空行
Insert(str);
}
while( gets(str)) cout << Find(str) << endl;
return 0;
}
#include <bits/stdc++.h>
using namespace std;
struct Trie{ //字典树定义
Trie* next[26];
int num; //以当前字符串为前缀的单词的数量
Trie() { //构造函数
for(int i=0;i<26;i++) next[i] = NULL;
num=0;
}
};
Trie root;
void Insert(char str[]){ //将字符串插入到字典树中
Trie *p = &root;
for(int i=0;str[i];i++){ //遍历每一个字符
if(p->next[str[i]-'a']==NULL) //如果该字符没有对应的结点
p->next[str[i]-'a'] = new Trie; //创建一个
p = p->next[str[i]-'a'];
p->num++;
}
}
int Find(char str[]){ //返回以字符串为前缀的单词的数量
Trie *p = &root;
for(int i=0;str[i];i++){ //在字典树找到该单词的结尾位置
if(p->next[str[i]-'a']==NULL)
return 0;
p = p->next[str[i]-'a'];
}
return p->num;
}
int main(){
char str[11];
while(gets(str)){
if ( !strlen(str) ) break; //输入了一个空行
Insert(str);
}
while( gets(str)) cout << Find(str) << endl;
return 0;
}