nyoj 230 涂彩棒 并查集 字典树 欧拉

彩色棒

时间限制:1000 ms  |  内存限制:128000 KB
难度:5
描述
You are given a bunch of wooden sticks. Each endpoint of each stick is colored with some color. Is it possible to align the sticks in a straight line such that the colors of the endpoints that touch are of the same color?
输入
the frist line have a number k(0<k<=10),that is the number of case. each case contais a number m,then have m line, each line contains two words, separated by spaces, giving the colors of the endpoints of one stick. A word is a sequence of lowercase letters no longer than 13 characters. There is no more than 250000 sticks.
输出
If the sticks can be aligned in the desired way, output a single line saying Possible, otherwise output Impossible.
样例输入
1
5
blue red
red violet
cyan blue
blue magenta
magenta cyan
样例输出
Possible
#include<stdio.h>
#include<string.h>
#include<malloc.h>
struct node
{
    int order;
    struct node *next[26];
};

int  t;//记录颜色种类
int father[250001];//记录并查集父亲节点
int degree[250001];//记录每种颜色出现的次数
int insert(char *str,node *T)//插入构建字典树
{
    int len,id,flat=0,i,j;
    node *p,*q;
    len=strlen(str);
    p=T;
    for(i=0;i<len;++i)
    {
        id=str[i]-'a';
        if(p->next[id]==NULL)
        {
            flat=1;
            q=(node *)malloc(sizeof(node));
            for(j=0;j<26;++j)
                q->next[j]=NULL;
            p->next[id]=q;
        }
        p=p->next[id];
    }
    if(flat)//字典树向前延伸,出现新的颜色
    {
        p->order=t;//在此记录此种颜色的 序号
        degree[t++]++;//增加出现次数
        return p->order;
    }
    else
    {
        if(p->order==0)//可能有这种情况 abdse abd虽然没有延伸,但也是新颜色
        {
            p->order=t;
            degree[t++]++;
            return p->order;
        }
        degree[p->order]++;
        return p->order;
    }
}

int findfather(int i)
{
    if(father[i]==-1)
        return i;
    else
        return findfather(father[i]);
}

void merge(int a,int b)//合并 
{
    a=findfather(a);
    b=findfather(b);
    if(a!=b)
    {
        if(father[a]<father[b])
            father[b]=a;
        else
            father[a]=b;
    }
}

int main()
{
    char str1[14],str2[14];
    int flag,i,num1,num2,n,x;
    node *T;
    scanf("%d",&x);
    while(x--)
    {
        T=(node *)malloc(sizeof(node));
        T->order=0;
        memset(degree,0,sizeof(degree));
        memset(father,-1,sizeof(father));
        for(i=0;i<26;++i)
            T->next[i]=NULL;
        t=1;
        scanf("%d",&n);
        if(n==0)
        {
            printf("Possible\n");
            continue;
        }
        while(n--)
        {
            scanf("%s%s",str1,str2);
            num1=insert(str1,T);
            num2=insert(str2,T);
            merge(num1,num2);
        }
        flag=0;
        for(i=1;i<t;++i)
            if(father[i]==-1)//统计根节点
                ++flag;
        if(flag>1)
            printf("Impossible\n");
        else
        {
            flag=0;
            for(i=1;i<t;++i)
                if(degree[i]&1)
                    flag++;
            if(flag==2||flag==0)
                 printf("Possible\n");
            else
                 printf("Impossible\n");
        }
    }
    return 0;
}



            

泪奔啊,刚开始想着和单词连接很像,就把那个代码作了一点改动,一直超时,后来 胖子说他做字典树用的并查集。并查集对于大数据量有很快的效率,这个题是25万的数据,看来就是考这点啦。用了并查集,果然过啦

思路:

先把数据存储到字典树里面,字典树再这路的作用有两个:一个是统计颜色种类,一个是每种颜色数量。然后用并查集,讲这些颜色合并。每次输入都合并。到最后统计下 根节点的数量,就是并查集的数量,如果大于1,说明不单单在一个集合,绝对不能连成线,如果是,则要根据 欧拉通路的原理去判定

原文地址:https://www.cnblogs.com/zibuyu/p/2960916.html