POJ3630 Phone List+字典數三種申請內存的方法--動態、靜態、半動態

POJ3630Phone List+字典數三種動態和靜態申請內存的方法  

Description:

Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another. Let's say the phone catalogue listed these numbers:

  • Emergency 911
  • Alice 97 625 999
  • Bob 91 12 54 26

In this case, it's not possible to call Bob, because the central would direct your call to the emergency line as soon as you had dialled the first three digits of Bob's phone number. So this list would not be consistent.

Input

The first line of input gives a single integer, 1 ≤ t ≤ 40, the number of test cases. Each test case starts with n, the number of phone numbers, on a separate line, 1 ≤ n ≤ 10000. Then follows n lines with one unique phone number on each line. A phone number is a sequence of at most ten digits.

Output

For each test case, output "YES" if the list is consistent, or "NO" otherwise.

Sample Input

2
3
911
97625999
91125426
5
113
12340
123440
12345
98346
Sample Output

NO
YES

題意很簡單:就是給你一系列的字符串,容易過其中有一個字符串是其中一個字符串的前綴,就輸出NO,否則輸出YES。

解題思路也不難,只要在建樹把字符串一個個放進去,然後邊放邊判斷。這裏要注意的是判斷的時候分類討論:1、現在判斷的字符串之前放進去的字符串的前綴 2、之前放進去的字符串是現在判斷的字符串的前綴。


這裏然後介紹三種申請內存的方法

1、動態申請內存,這個是三種裏面速度最慢的,因爲要逐個的去申請結構體的內存。(針對這道題目,在杭電的HDU1671能過,但在POJ上卻過不了,這個讓我當初在POJ上TLE了無數次)

<pre name="code" class="html">#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 10
char s[30];
bool flag;
typedef struct tree{
    tree *next[MAX];
    bool v;
};
tree *root;
void creattree(char *str)
{
    tree *p=root,*q;
    int n=strlen(str);
    for(int i=0;i<n;i++)
    {
        int id=str[i]-'0';
        if(p->next[id]==NULL)
        {
            q=(tree *)malloc(sizeof(tree));    ///動態申請內存
            q->v=0;
            for(int j=0;j<MAX;j++)
            {
                q->next[j]=NULL;
            }
            p->next[id]=q;
            p=p->next[id];
        }
        else
        {
            p=p->next[id];
            if(p->v||i==n-1) {flag=1;break;}
        }
    }
    p->v=1;
}
int dele(tree *t)
{
    if(t==NULL) return 0;
    else
    {
        for(int i=0;i<MAX;i++)
        {
            if(t->next[i]!=NULL)
                dele(t->next[i]);
        }
    }
    free(t);
    return 0;
}
int main()
{
    int to;
    scanf("%d",&to);
        while(to--)
        {
            root=(tree *)malloc(sizeof(tree));      //動態申請內存
            root->v=0;
            for(int i=0;i<MAX;i++) root->next[i]=NULL;
            int n;
            flag=0;
            scanf("%d",&n);
            for(int i=0;i<n;i++)
            {
                scanf("%s",s);
                if(!flag) creattree(s);
            }
            if(flag) printf("NO\n");
                else printf("YES\n");
                dele(root);
        }
}






第二種是靜態申請內存,也就是開個結構體數組,這種方法耗時最短,但是有個壞處就是如果題目沒有告訴你要申請的結構體的數目,你開太少的話會RE,開太多容易爆掉,不過這種寫法還是最普及的寫法。(這種寫法在POJ3630和HDU1671都能過)

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 10
const int N = 1000000;
char s[30];
bool flag;
typedef struct tree{
    tree *next[MAX];
    bool v;
};
tree dot[N],*bat;     ///申請結構體數組
tree *newNode()
{
    tree *p = bat++;
    for(int i=0;i<MAX;i++)
    {
        p->next[i]=NULL;
        p->v=0;
    }
    return p;
}
tree *root;
void creattree(char *str)
{
    tree *p=root,*q;
    int n=strlen(str);
    for(int i=0;i<n;i++)
    {
        int id=str[i]-'0';
        if(p->next[id]==NULL)
        {
            q=newNode();
            p->next[id]=q;
            p=p->next[id];
        }
        else
        {
            p=p->next[id];
            if(p->v||i==n-1) {flag=1;break;}
        }
    }
    p->v=1;
}
void memin()
{
    bat=dot;
    root=newNode();
}
int main()
{
    int to;
    scanf("%d",&to);
        while(to--)
        {
            memin();
            int n;
            flag=0;
            scanf("%d",&n);
            for(int i=0;i<n;i++)
            {
                scanf("%s",s);
                if(!flag) creattree(s);
            }
            if(flag) printf("NO\n");
                else printf("YES\n");
        }
}
第三種方法爲半動態申請,這種方法在處理上應該是最優的,既克服了動態申請內存時間太慢的缺點,又避免了靜態申請內存數組大小不好控制的缺點。這種方法的原理就是一次性申請一個範圍適中的結構體數組,比如這題可以開個10000,然後不夠的時候再開,但是要把這些結構體給連上,最後拿來重新利用。實現方法如下:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 10
const int N = 10000;
char s[30];
bool flag;
typedef struct tree{
    tree *next[MAX];
    bool v;
};
tree *List;
tree *newNode()
{
    if(List==NULL)				//如果10000個結構體用完可以繼續申請
    {
        tree *p=new tree[10000];
        for(int i=0;i<10000;i++)
        {
            p[i].next[0]=List;		///這裏兩行把結構體連接起來
            List=p+i;			///
        }
    }
    tree *p=List;
    List=List->next[0];
    for(int i=0;i<MAX;i++)
    {
        p->next[i]=NULL;
        p->v=0;
    }
    return p;
}
tree *root;
void creattree(char *str)
{
    tree *p=root,*q;
    int n=strlen(str);
    for(int i=0;i<n;i++)
    {
        int id=str[i]-'0';
        if(p->next[id]==NULL)
        {
            q=newNode();
            p->next[id]=q;
            p=p->next[id];
        }
        else
        {
            p=p->next[id];
            if(p->v||i==n-1) {flag=1;break;}
        }
    }
    p->v=1;
}
void reuse(tree *o)			///退回去重新利用
{
    if(o==NULL) return;
    for(int i=0;i<MAX;i++)
    {
        reuse(o->next[i]);
    }
    o->next[0] = List;
    List = o;
}
int main()
{
    int to;
    scanf("%d",&to);
        while(to--)
        {
            root=newNode();
            int n;
            flag=0;
            scanf("%d",&n);
            for(int i=0;i<n;i++)
            {
                scanf("%s",s);
                if(!flag) creattree(s);
            }
            if(flag) printf("NO\n");
                else printf("YES\n");
                reuse(root);
        }
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章