字典树

vj地址

一共9题

A - 统计难题 HDU - 1251

题意:给很多字符串,然后在这些串中查询公共前缀的数量

分析:字典树模板题

//from : 1610300216

#include 
#include 
using namespace std;
#include 
#include 
#include 
#include 
const int maxn = 26;


struct Trie
{
    Trie *Next[maxn];
    int sum;//jishu
    Trie()
    {
        sum = 0;
        for(int i = 0; i < maxn; i++)
            Next[i] = NULL;
    }
};
Trie *root;
void CreatTrie(char *str)
{
    int len = strlen(str);
    len --; //因为主函数里读取字符串用的是fgets,会把'\n'读进去,故len--
    Trie *p = root, *q;
    for(int i = 0; i < len; i++)
    {
        int id = str[i] - 'a';// 求下标。ASC表的如 b-a 等于1
        if(p->Next[id] == NULL)
        {//空表时
            q = new Trie();
            q->sum = 1;
            p->Next[id] = q;
            p = p->Next[id];
        }
        else
        {
            p->Next[id]->sum ++; //不是空表,记录出现次数
            p = p->Next[id];
        }
    }
}

int FindTrie(char *str)
{
    int len = strlen(str);
    Trie *p = root;
    for(int i = 0; i < len; i++)
    {
        int id = str[i] - 'a'; //同上
        if(p->Next[id] == NULL)
            return 0;
        else p = p->Next[id];
    }
    return p->sum;
}
void release(Trie *p)
{
    if(p==NULL)
        return ;
    for(int i = 0; i < maxn; i++)
        if(p->Next[i]!=NULL)
            release(p->Next[i]);
    free(p);
    root=NULL;
    return ;
}
int main()
{
    char str[15];
    root = new Trie(); // root要给新空间
    while(fgets(str,15,stdin) && strcmp(str,"\n") != 0) //“stdin”标准输入,从键盘输入
    {
        CreatTrie(str);
    }
    while(scanf("%s",str) != EOF)
    {
        int total = FindTrie(str);
        printf("%d\n",total);
    }
    release(root);
    return 0;
}

B - Immediate Decodability HDU - 1305

题意:有很多字符串,问有没有串是别的串的前缀。

分析:这里在字典树的建树中就可以判断出来了。若字符串A是B的前缀,有两种可能,若B先建树,A建树的过程中是没有节点为空的,也就是不会新建节点。若A先建树,B在建树的过程中就会经过A。


#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
#define maxn 5
#define LL long long
struct Trie
{
    int v;
    Trie *next[maxn];
    Trie()
    {
        v=0;
        for(int i=0;iint sert(char *str)
{
    int g=0,flag=0;
    int len=strlen(str);
    Trie *p=root;
    for(int i=0;iint id=str[i]-'0';
        if(p->next[id]==NULL)
        {
            g=1;//新建节点
            p->next[id]=new Trie;
        }
        p=p->next[id];
        if(p->v) flag=1;//有没有经过别的字符串
    }
    p->v=1;
    if(flag==1||g==0) return 0;
    else return 1;
}
void del(Trie *p)
{
    if(p==NULL) return ;
    for(int i=0;iif(p->next!=NULL) del(p->next[i]);
    }
    delete p;
}
int main()
{
    char s[20];
    root=new Trie;
    int gg=0;
    int case1=1;
    while(scanf("%s",s)!=EOF)
    {
        if(s[0]=='9') {
            if(gg) printf("Set %d is not immediately decodable\n",case1++);
            else printf("Set %d is immediately decodable\n",case1++);
            del(root);
            root=new Trie;
            gg=0;
            continue;
        }
        if(!sert(s)) gg=1;
    }
    return 0;
}

C - What Are You Talking About HDU - 1075

题意 :一本英文-火星的字典,给你几组英文和火星文的字符串,给你一句火星文,翻译出来,如果字典里没有那句火星文的话,直接将火星文输出。字典里的字符都是小写英文字母;

分析:将字典中的火星词建树,然后将对应的英文词存起来。翻译的时候直接在树上找就好了。这里注意一下字符串的处理就行了

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
#define maxn 26
#define LL long long
char s[3000000][15];
struct Trie
{
    int v;
    Trie *next[maxn];
    Trie()
    {
        v=0;
        for(int i=0;ivoid sert(char *str,int h)
{
    int len=strlen(str);
    Trie *p=root;
    for(int i=0;iint id=str[i]-'a';
        if(p->next[id]==NULL)
            p->next[id]=new Trie;
        p=p->next[id];
    }
    p->v=h;
}
void del(Trie *p)
{
    if(p==NULL) return ;
    for(int i=0;iif(p->next!=NULL) del(p->next[i]);
    }
    delete p;
}
int findf(char *str)
{
    int len=strlen(str);
    Trie *p=root;
    for(int i=0;iint id=str[i]-'a';
        if(p->next[id]==NULL) return 0;
        p=p->next[id];
    }
    if(p->v==0) return 0;
    else {
        printf("%s",s[p->v]);
        return 1;
    }
}

int main()
{
    char s1[15],s2[15];
    int h=1;
    root=new Trie;
    while(scanf("%s",s[h]))
    {
        if(strcmp(s[h],"START")==0) continue;
        else if(strcmp(s[h],"END")==0) break;
        scanf("%s",s2);
        sert(s2,h);h++;
    }
    char c,g=0;
    getchar();
    c=getchar();
    while(1)
    {
        while(c>='a'&&c<='z'){
            s2[g++]=c;
            c=getchar();
        }
        s2[g]='\0';
        if(g>0) {
            if(!findf(s2)) printf("%s",s2);
            g=0;
        }
        else if(c=='S')
        {
            for(int i=0;i<6;i++) c=getchar();
        }
        else if(c=='E') {
            getchar();getchar();getchar();break;
        }
        else {printf("%c",c);c=getchar();}
    }
    del(root);
    return 0;
}

也可以用map

//from : 742962178

#include
#include
#include
#include
#include
using namespace std;
int main()
{
    map<string, string> m;
    char s1[10],s2[10];
    char temp[10];
    string str;
    while (scanf("%s",s1)) {
        if (s1[0] == 'S')
            scanf("%s", s1);
        if (s1[0] == 'E')
            break;
        scanf("%s", s2);
        m[s2] = s1;
    }
    scanf("%s", temp);
    getchar();
    char ch=' ';
    while (scanf("%c",&ch)) {
        if (isalpha(ch))
            str += ch;
        else {
            if (str[0] == 'E')break;
            if (m.find(str) != m.end())
                cout << m[str];
            else cout << str;
            printf("%c", ch);
            str.clear();
        }
    }
    return 0;
}

D - Hat’s Words HDU - 1247

题意: 有很多字符串,问其中哪个字符串是有其他两个字符串组成的

分析:先将全部字符串都建树,然后将每个字符串分成两个字符串在字典树中查找,如果都找到了,就是它~~

//from : Next
#include 
#include 
#include 
#include 
using namespace std;
#define mx 26
#define mxn 26
typedef struct Trie
{
    Trie *next[mx];
    int v;
    Trie()
    {
        v=0;
        for(int i=0; ichar s[50003][117],p[mxn];
Trie *root;
void creTrie(char *s)
{
    int len=strlen(s);
    Trie *p=root,*q;
   // len--;
    for(int i=0; iint id=s[i]-'a';
        if(p->next[id]==NULL)
        {
            q=new Trie();
            q->v=1;
            for(int j=0; jnext[j]=NULL;
            p->next[id]=q;
            p=p->next[id];
        }
        else
        {
            //p->next[id]->v++;
            p=p->next[id];
        }
    }
    p->v=-1;
}
int searchs(char* rp)
{
    int len=strlen(rp);
    Trie *p=root;
    for(int i=0; iint id=rp[i]-'a';
        p=p->next[id];
        if(p==NULL)return 0;
       // else return 0;

    }
    if(p->v==-1)return-1;
    else return 0;
}

void dealTrie(Trie* t)
{
    if(t==NULL)return;
    for(int i=0; iif(t->next[i]!=NULL)dealTrie(t->next[i]);
    free(t);
    root=NULL;
    return;
}
int main()
{
    root=new Trie();
    int cnt=0;
    while(scanf("%s",s[cnt])!=EOF)
    {
        creTrie(s[cnt]);cnt++;
    }
    char a[103],b[103];
    for(int i=0; iint len = strlen(s[i]);
        for(int j=1; jmemset(a,'\0',sizeof(a));
            memset(b,'\0',sizeof(b));
            strncpy(a,s[i],j);
            strncpy(b,s[i]+j,len-j);
            if(searchs(a)==-1&&searchs(b)==-1)
            {
                cout<break;
            }
        }
    }
    return 0;
}

E - Phone List HDU - 1671

这一题竟然和B题一模一样,惊不惊喜。。改一点点就可以交了~~

F - Repository HDU - 2846

题意:给n个字符串,有q个提问,问这个字符串在给的n个字符串中有没有出现过。

分析:先将n个字符串建树,每个字符串,如s[0,1,2,…len-1],将s[0,1,2,…len-1],s[1,2,…len-1],s[2,3…len-1],一直到s[len-1]建树。然后在字典树种每个字符串出现的次数记录一下,注意,由同一个字符串建树,出现的次数应该为1.比如abab,这里a出现的次数应该是1。最后查询即可

//from : caijichang

#include
#include
#include

using namespace std;


struct trie{

    int v;
    int m;    //是否重复; 
    trie *next[26];
    trie(){
        v=0;
        for(int i=0;i<26;i++)
        {
            m=-1;
            v=0; 
            next[i]=NULL;
        }
    }
}; 

trie *root;

void creat(trie *root,char *str,int k)
{
    trie *p=root;
    for(;*str;str++)
    {
        int sign=*str-'a';
        if(p->next[sign]==NULL)
        {
            p->next[sign]=new trie();
        }
        p=p->next[sign];
        if(p->m!=k)
        {
            p->m=k;
            p->v++;         
        }
    }
}

int find(trie *root,char *str)
{
    int len=strlen(str);
    trie *p=root;
    for(int i=0;iint id=str[i]-'a';
        if(p->next[id]==NULL)
        {
            return 0;
        }
        p=p->next[id];
    }
    return p->v;
}

void del(trie *root)
{
    for(int i=0;i<26;i++)
    {
        if(root->next[i])
        {
            del(root->next[i]); 
        }
    }
    delete(root);
}

int main()
{
    int n,m;
    char s[30];
    root=new trie();
    cin>>n;
    while(n--)
    {
        scanf("%s",s);
        for(int j=0;j<strlen(s);j++)
        {
            creat(root,s+j,n);
        }
    }
    cin>>m;
    while(m--)
    {
        scanf("%s",s);
        cout<return 0;
}

G - Problem C HDU - 5687

题意:中文题,应该看得懂~

分析:主要是删除这操作,找到那个点后,我们要删掉后面的,也要删掉前面的。

//from : 742962178

#include
#include
#include
#include
using namespace std;
const int maxn = 26;
struct Trie
{
    Trie *next[maxn];
    int v;
    Trie() {
        v = 0;
        memset(next, NULL, sizeof(next));
    }
};
Trie* root;
void insertTrie(string str)
{
    int len = str.size();
    Trie *p = root;
    for (int i = 0; i < len; i++) {
        int id = str[i] - 'a';
        if (!p->next[id]) {
            p->next[id] = new Trie();
            p->next[id]->v = 1;
            p = p->next[id];
        }
        else {
            p->next[id]->v++;
            p = p->next[id];
        }
    }
}
void release(Trie *p)
{
    if (p == NULL)
        return;
    for (int i = 0; iif (p->next[i])
            release(p->next[i]);
    p = NULL;
    delete p;
    return;
}
void deleteTrie(string str)
{
    int len = str.size();
    Trie *p = root, *pre;
    int i = 0;
    for (i = 0; i < len; i++) {
        int id = str[i] - 'a';
        if (p->next[id]) {
            pre = p;
            p = p->next[id];
        }
        else break;
    }
    if (str[i] == '\0') {
        int num = p->v;
        Trie *q = root;
        release(p);
        pre->next[str[len - 1] - 'a'] = NULL;
        for (int i = 0; i < len - 1; i++) {
            q = q->next[str[i] - 'a'];
            q->v -= num;
        }
    }
}
void searchTrie(string str)
{
    int len = str.size();
    Trie *p = root;
    for (int i = 0; i < len; i++) {
        int id = str[i] - 'a';
        if (!p->next[id]) {
            printf("No\n");
            return;
        }
        p = p->next[id];
    }
    if (p->v < 1)
        printf("No\n");
    else printf("Yes\n");
    return;
}
int main()
{
    int n = 0;
    scanf("%d", &n);
    root = new Trie();
    while (n--) {
        char s1[10];
        char s2[35];
        scanf("%s%s", s1, s2);
        switch (s1[0])
        {
        case 'i':insertTrie(s2); break;
        case 's':searchTrie(s2); break;
        case 'd':deleteTrie(s2); break;
        default:
            break;
        }
    }
    release(root);
    return 0;
}

后面两题就直接上代码了…

H - Babelfish POJ - 2503

//from : caijichang

#include
#include
#include

using namespace std;

char s[20];
char s1[100005][20];
int num=1;

struct trie{
    int v; 
    trie *next[26];
    trie(){
        for(int i=0;i<26;i++)
        {
            v=0;
            next[i]=NULL;
        }
    }
}; 

trie *root;
bool flag;

void creat(trie *root,char *str)
{
    int len=strlen(str);
    trie *p=root,*q;
    for(int i=0;iint sign=str[i]-'a';
        if(p->next[sign]==NULL)
        {
            q=new trie();
            p->next[sign]=q;
            p=p->next[sign];
        }
        else
        {
            p=p->next[sign];            
        }
    }
    p->v=num;
    num++;
}

int find(trie *root,char *str)
{
    int len=strlen(str);
    trie *p=root;
    for(int i=0;iint id=str[i]-'a';
            p=p->next[id];
            if(p==NULL)
            {
                cout<<"eh"<return 0;
            }       
    }
    return p->v;
}

void del(trie *root)
{
    for(int i=0;i<26;i++)
    {
        if(root->next[i])
        {
            del(root->next[i]); 
        }
    }
    delete(root);
}

int main()
{
    root=new trie();
    int count=0;
    char str1[50];
    while(gets(str1))
    {
        if(str1[0]=='\0')
            break;
        sscanf(str1,"%s%s",s1[count],s);
        count++;
        creat(root,s);
    }
    while(scanf("%s",s)!=EOF)
    {
        int n=find(root,s);
        if(n>0)
        {
            cout<1]<return 0;
}

I - Shortest Prefixes POJ - 2001

//from : 742962178

#include
#include
#include
using namespace std;
const int maxn = 26;
struct Trie
{
    Trie *next[maxn];
    int v;
    Trie() {
        v = 0;
        memset(next, NULL, sizeof(next));
    }
};
Trie *root;
void createTrie(string str)
{
    int len = str.size();
    Trie* p = root, *q;
    for (int i = 0; i < len; i++) {
        int id = str[i] - 'a';
        if (p->next[id] == NULL) {
            p->next[id] = new Trie();
            p->next[id]->v = 1;
            p = p->next[id];
        }
        else {
            p->next[id]->v++;
            p = p->next[id];
        }
    }
}
string findTrie(string str)
{
    int len = str.size();
    Trie *p = root;
    for (int i = 0; i < len; i++) {
        int id = str[i] - 'a';
        if (p->next[id] != NULL) {
            p = p->next[id];
            if (p->v == 1)
                return string(str.begin(), str.begin()+i+1);
        }
    }
    return str;
}
void release(Trie *p)
{
    if (p == NULL)
        return;
    for (int i = 0; iif (p->next[i] != NULL)
            release(p->next[i]);
    free(p);
    root = NULL;
    return;
}
int main()
{
    string s[1005];
    int n = 0;
    root = new Trie();
    while (cin >> s[n++]) {
        createTrie(s[n - 1]);
    }
    for (int i = 0; i < n; i++) {
        cout << s[i] <<" "<< findTrie(s[i]) << endl;
    }
    release(root);
    return 0;
}

你可能感兴趣的:(暑假集训)