hdu2846(字典树)
http://acm.hdu.edu.cn/showproblem.php?pid=2846
思路:题目属于判断字符串中是否包含子串的问题,对于一般的字典树,用来判断前缀,而这里不能直接这么去建树。在建树的时候将字符串X=X1X2....Xn的分别以X1,X2....Xn开头的后缀子串插入到Trie树中,如此一来就可以判断某个字符串是否被包含在另一个字符串当中。当然,这里还有个问题,比如插入了字符串abab,那么当查找字符串ab时就会重复计数,因此需要多设计一个标识以表示在插入"abab"和"ab"时时同一个字符串即可(是同一个字符串就不需要使计数器加1),因此在Trie树结点中多设计一个商品id来标记。id用来记录最后一个经过此路径上的商品编号,如果要插入的字符串编号同当前节点的编号不同,则计数器加1,并且将当前结点的编号置为要插入的字符串的编号。
#include<iostream> #include<string.h> using namespace std; typedef struct tree { int id; //最后一次经过此结点的商品ID int num; //记录包含该结点的单词个数 tree *next[26]; }tree; char s[25]; tree *root=(tree *)malloc(sizeof(tree)); void creat(char str[],int k) { int len=strlen(str); tree *p=root,*q; for(int i=0;i<len;i++) { int x=str[i]-'a'; if(p->next[x]==NULL) { q=(tree *)malloc(sizeof(tree)); q->id=k; q->num=1; for(int j=0;j<26;j++) q->next[j]=NULL; p->next[x]=q; } p=p->next[x]; if(p->id!=k) //如果当前结点的商品ID不等于要插入商品的ID,则计数器num++,并且重新置ID的值 { p->id=k; p->num++; } } } int find(char str[]) { int len=strlen(str); tree *p=root; for(int i=0;i<len;i++) { int x=str[i]-'a'; if(p->next[x]) p=p->next[x]; else return 0; } return p->num; } void del(tree *root) { for(int i=0;i<26;i++) { if(root->next[i]) del(root->next[i]); } free(root); } int main() { int n,m; for(int i=0;i<26;i++) root->next[i]=NULL; root->num=0; root->id=-1; scanf("%d",&n); for(i=0;i<n;i++) { scanf("%s",s); int len=strlen(s); for(int j=0;j<len;j++) //将字符串X=X1X2...Xn的分别以X1,X2...Xn开头的后缀字符串插入到Tree树中 { creat(s+j,i); } } scanf("%d",&m); while(m--) { scanf("%s",s); printf("%d\n",find(s)); } del(root); return 0; }
朋友们,虽然这个世界日益浮躁起来,只要能够为了当时纯粹的梦想和感动坚持努力下去,不管其它人怎么样,我们也能够保持自己的本色走下去。