POJ 2513 (Trie树+欧拉通路+并查集判断连通)

题目:http://poj.org/problem?id=2513

两个教训:

  一、输入输出用scanf、printf(好像自己已经强调很多遍了= =……)

    eg:用cin 1000MS 用scanf 400MS…………

  二、不要把string作为函数值传递参数(推广到整个STL,STL加了很多没用的功能会导致效率变低) 

     eg:此题Trie中的参数用string 4485MS 用char * 985MS…………

/*
题目大意:每个木棒头尾都有两种颜色,木棒末端颜色相同的可以连接成一条直线,问能否将所有木棒连接起来组成一条直线。
题目求解:传换成图的问题就是求解能否一笔画成(欧拉通路)
代码技巧:用数组字典树和链表字典树都可以,动态链表空间少好写,静态数组速度快,看情况吧。
*/

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <iomanip>
#include <climits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <string>
#include <cstring>

using namespace std;

#define N 500005

struct set
{
    int parent;  //记录父节点
    int rank;    //记录集合的节点数
}elem[N];

int MAX;

void init()
{
    int i;
    for(i=0;i<=N;i++)
    {
        elem[i].parent=i;
        elem[i].rank=1;
    }
}

int Find(int x)
{
    int root,temp;
    temp=x;
    while(x!=elem[x].parent)    //寻找根节点
        x=elem[x].parent;
    root=x;
    x=temp;
    while (x!=elem[x].parent)   //压缩路径,全部赋值为根节点的值
    {
        temp=elem[x].parent;
        elem[x].parent=root;
        x=temp;
    }
    return root;
}

void Union(int a,int b)   //合并两个集合
{
    int x,y;
    x=Find(a);
    y=Find(b);
    if(elem[x].rank>=elem[y].rank)
    {
        elem[y].parent=elem[x].parent;
        elem[x].rank+=elem[y].rank;
        if(MAX<elem[x].rank)
            MAX=elem[x].rank;
    }
    else
    {
        elem[x].parent=elem[y].parent;
        elem[y].rank+=elem[x].rank;
        if(MAX<elem[y].rank)
            MAX=elem[y].rank;
    }
}
//Trie树模板   by AbandonZHANG


int words_num;
int degree[500005];

struct Trie_node
{
    //int Ch_Count;   //统计单词个数,如果为0表示没有该串。
    int hash;       //单词hash后的标识数
    Trie_node *next[26];//指向各个子树的指针,下标0-25代表26字符,如果是数字改成10就行了
    Trie_node()
    {
        //Ch_Count=0;
        hash=-1;
        memset(next,NULL,sizeof(next));
    }
};

class Trie
{
public:
    Trie();
    int insert(char *word);                //插入新单词
private:
    Trie_node* root;
};

Trie::Trie()
{
    root = new Trie_node();
}

int Trie::insert(char *word)               //边插入边查找
{
    Trie_node *p = root;
    int len=strlen(word);
    if(len==0) return -1;
    for (int i=0;i<len;i++)
    {
        if(p->next[word[i]-'a'] == NULL)      //如果不存在的话,我们就建立一个新的节点
        {
            Trie_node *tmp = new Trie_node();
            p->next[word[i]-'a'] = tmp;
            p = p->next[word[i]-'a'];         //每插入一步,相当于有一个新串经过,指针要向下移动
        }
        else                                //如果这个节点之前就已经存在呃,我们只需要把统计次数加上1
            p=p->next[word[i]-'a'];
        //p->Ch_Count++;                      //这里是求所有前缀出现的次数,如果只求整个单词出现次数则用后一个
    }
    //p->Ch_Count++;                              //求整个单词的出现次数

    if (p->hash<0)
        p->hash=words_num++;

    return p->hash;
}

Trie t;


int main()
{
    //freopen("test.in","r",stdin);

    init();
    char a1[15],a2[15];
    words_num=0;
    while(scanf("%s%s",a1,a2)!=EOF)
    {
        int x,y;
        x=t.insert(a1);
        degree[x]++;
        y=t.insert(a2);
        degree[y]++;
        Union(x,y);
    }
    int sum=0;
    for (int i=0;i<words_num;i++)
    {
        if (degree[i]%2==1)
            sum++;
        if (sum>2)
        {
            printf("Impossible\n");
            return 0;
        }
    }

    for (int i=0;i<words_num;i++)
        if (Find(i)!=Find(0))
        {
            printf("Impossible\n");
            return 0;
        }
    printf("Possible\n");
    return 0;
}
posted @ 2012-08-07 14:17  AbandonZHANG  阅读(254)  评论(0编辑  收藏  举报