模型:单词匹配
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct node
{
bool flag;
string s;
node *next[26];
node()
{
flag=0;
memset(next,0,sizeof(next));
}
};
node *p,*root;
void Insert(string s,string v)
{
p=root;
for(int i=0;i<s.size();i++)
{
int id=s[i]-'a';
if(p->next[id]==NULL) p->next[id]=new node();
p=p->next[id];
}
p->flag=1;//终点标志,若改成++,则得出该单词出现的次数
p->s=v;
}
string Query(string s)
{
p=root;
for(int i=0;i<s.size();i++)
{
int id=s[i]-'a';
if(p->next[id]==NULL) return "";
p=p->next[id];
}
if(p->flag==0) return "";
return p->s;
}
int main()
{
root=new node();
string s,v;
cin>>s;
while(cin>>s&&s!="END")
{
cin>>v;
Insert(v,s);
}
cin>>s;
getline(cin,s);
while(getline(cin,s)&&s!="END")
{
for(int i=0;i<s.size();i++)
{
v="";
while(s[i]>='a'&&s[i]<='z') v+=s[i++];
string f=Query(v);
if(f=="") cout<<v<<s[i];
else cout<<f<<s[i];
}
cout<<endl;
}
return 0;
}
hud2846
大意:给定你一些商品的信息save(字符串),然后输入需要查询的字符串str,如果存在一个字符串save使得str是save的子串。
思路:字典树的变形,如存在"abcd",则"bcd", "cd", "d",都需要插入字典树中。如果存在"abab"的话,有可能"ab"会重复计数,所以需要一个特定的序列号来区分是否是同一序列中的子串。
我们可以定义一个value,若value相同,则跳过,若不同,则+1后更新value。
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
using namespace std;
struct node
{
int num,id;
node *next[26];
node() { num=0;id=0;memset(next,0,sizeof(next));}
};
node *p,*root;
void Insert(string s,int cnt)
{
p=root;
for(int i=0;i<s.size();i++)
{
int id=s[i]-'a';
if(p->next[id]==0)
{
p->next[id]=new node();
p=p->next[id];
p->id=cnt;
p->num++;
}
else
{
p=p->next[id];
if(p->id!=cnt)
{
p->id=cnt;
p->num++;
}
}
}
}
int Query(string s)
{
p=root;
for(int i=0;i<s.size();i++)
{
int id=s[i]-'a';
if(p->next[id]==0) return 0;
p=p->next[id];
}
return p->num;
}
void Delete(node *rt)
{
for(int i=0;i<26;i++)
{
if(rt->next[i])
{
Delete(rt->next[i]);
delete(rt->next[i]);
}
}
}
int main()
{
int n;
string s;
cin.sync_with_stdio(false);
while(cin>>n)
{
root=new node();
for(int i=0;i<n;i++)
{
cin>>s;
for(int j=0;j<s.size();j++)
Insert(s.substr(j),i);
}
int m;
cin>>m;
for(int i=0;i<m;i++)
{
cin>>s;
cout<<Query(s)<<endl;
}
Delete(root);
}
return 0;
}
hdu 1247
给出若干个单词,找出其中能够由其它两个单词连接组合而成的单词。比如上面sample中的"ahat"能够由"a"和"hat"拼凑而成,"hatword"="hat"+"word".
只要将这些字符串插入到字典树中去,并设置结束标记,并用字符串数组保存起来。然后再依次把每个字符串放到字典树中查询即可。
#include<iostream>
#include<cstring>
using namespace std;
const int maxn=100005;
string s[maxn];
struct node
{
bool f;
node *next[26];
node(){ f=0;memset(next,0,sizeof(next));}
};
node *root=new node();
void Insert(string s)
{
node *p=root;
for(int i=0;i<s.size();i++)
{
int id=s[i]-'a';
if(p->next[id]==NULL) p->next[id]=new node();
p=p->next[id];
}
p->f=1;
}
bool Find(string s)
{
if(s=="") return 0;
node *p=root;
for(int i=0;i<s.size();i++)
{
int id=s[i]-'a';
p=p->next[id];
if(p==0) return 0;
}
return p->f;
}
bool Query(string s)
{
node *p=root;
for(int i=0;i<s.size()-1;i++)
{
int id=s[i]-'a';
p=p->next[id];
if(p==0) return 0;
if(p->f&&Find(s.substr(i+1))) return 1;
}
return 0;
}
int main()
{
string str;
int pos=0;
while(cin>>str)
{
s[pos++]=str;
Insert(str);
// if(pos==6) break;
}
for(int i=0;i<pos;i++)
if(Query(s[i])) cout<<s[i]<<endl;
return 0;
}
题意:给出斐波那契数列的前k位,k不超过40,找出最小的正整数n,满足F(n)的前k位与给定数的前k位相同,斐波那契数列的项数不超过100000。
解析:本题可以分为两步:
第一步就是预处理出100000项斐波那契数列的前40位,插入到字典树中。
第二步就是查询匹配求最小的n。
对于第一步,我们可以把斐波那契数列精确到50多位,然后只存40位即可,这样就防止进位的误差。在斐波那契数列加法过程中,我们只把它的前50多
位进行相加,不然存不下。
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
const int N=10;
int f1[65],f2[65],f3[65];
class Trie
{
public:
int v;
int flag;
Trie *next[N];
Trie()
{
v=-1;
memset(next,NULL,sizeof(next));
}
};
Trie *root;
void Insert(char *S,int ans)
{
int len=strlen(S);
Trie *p=root;
for(int i=0;i<len;i++)
{
int id=S[i]-'0';
if(p->next[id]==NULL)
p->next[id]=new Trie();
p=p->next[id];
if(p->v<0) p->v=ans;
}
}
int Find(char *S)
{
Trie *p=root;
int count;
int len=strlen(S);
for(int i=0;i<len;i++)
{
int id=S[i]-'0';
p=p->next[id];
if(p==NULL) return -1;
else count=p->v;
}
return count;
}
void Init()
{
int h;
char str[65]="1";
memset(f1,0,sizeof(f1));
memset(f2,0,sizeof(f2));
memset(f3,0,sizeof(f3));
f1[0]=1;f2[0]=1;
Insert(str,0);
for(int i=2;i<100000;i++)
{
memset(str,0,sizeof(str));
int r=0;
for(int j=0;j<60;j++)
{
f3[j]=f1[j]+f2[j]+r;
r=f3[j]/10;
f3[j]%=10;
}
for(int j=59;j>=0;j--)
if(f3[j])
{
h=j;
break;
}
int k=0;
for(int j=h;j>=0;j--)
{
str[k++]=f3[j]+'0';
if(k>=40) break;
}
Insert(str,i);
if(h>55)
{
for(int j=1;j<59;j++)
f3[j-1]=f3[j];
for(int j=1;j<59;j++)
f2[j-1]=f2[j];
}
for(int j=0;j<60;j++)
f1[j]=f2[j];
for(int j=0;j<60;j++)
f2[j]=f3[j];
}
}
int main()
{
root=new Trie();
Init();
char str[105];
int t,i,j,k=1;
scanf("%d",&t);
while(t--)
{
scanf("%s",str);
printf("Case #%d: ",k++);
int tmp=Find(str);
printf("%d\n",tmp);
}
return 0;
}