POJ_2513_Colored Sticks(字典树、并查集、欧拉路)

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

/************************************************************************/
/*
题意:给定一些木棒,木棒两端有颜色,求能否将木棒首尾相接连成直线保证节点处的
颜色相同。
解题思路:可以用欧拉路德知识来解决这道题,首先我们可以把木棒两端的颜色看成节
点,而木棒看成边。所以问题就转化为是否存在一笔画,经过图中每边一次以及每点一
次  。
无向图存在欧拉路的充要条件是:
1:图是连通的;
2:所有节点的度数为偶数,或者有且仅有两个读数为奇数的节点。
其中1我们使用并查集来判断,只要图是不连通的那么操作完成之后有多个祖先。
知识考查点:
1、字典树;
2、欧拉路:其中又考察了判断是否为连通图;
3、并查集 及其优化方法(路径压缩)。
输出:
POSSIBLE:  奇度数结点个数==0 或 ==2  且  图连通
IMPOSSIBLE:奇度数结点个数==1 或 >=3  或  图不连通
PS:注意创建TrieTree链表时,C++不存在NULL,要用 0 替代 NULL
                                                                   */
/************************************************************************/

  1 # include <stdio.h>
  2 # include <string.h>
  3 # include <algorithm>
  4 using namespace std;
  5 const int MAX=500000;
  6 struct node
  7 {
  8     bool flag; //标记到字典树从根到当前结点所构成的字符串是否为一个(颜色)单词   
  9     int id; //当前颜色节点的编号。出现几个单词id最大值就是几。
 10     struct node *next[27]; //记录字母a-z,转化成数字记录。
 11     struct node() //Initial
 12     {
 13         flag=false;
 14         id=0;
 15         memset(next,0,sizeof(next));
 16     }
 17 }root; //根节点,根节点不存值;
 18 int color=0; //颜色编号,出现几个最大就是几。
 19 int degree[MAX+1]={0}; //某个颜色(id)的总度数。
 20 int ancestor[MAX+1];  //第id个颜色的祖先。
 21 //寻找x节点的祖先。
 22 /*
 23 int find(int x)  //不含路径压缩;
 24 {
 25     while(x != ancestor[x])
 26     {
 27          x=ancestor[x];
 28     }
 29     return x;
 30 }
 31 */
 32 int find(int x) 
 33 {
 34     if(ancestor[x]!=x)
 35         ancestor[x]=find(ancestor[x]); //路径压缩
 36     return ancestor[x];
 37 }
 38 //合并集合,使得两者的祖先相同。
 39 void union_set(int a,int b)
 40 {
 41     int x=find(a);
 42     int y=find(b);
 43     ancestor[y]=x; //ancestor[x]=y;也行;
 44     return;
 45 }
 46 //利用字典树构造字符串s到编号int的映射 ;
 47 int hash(char *s)  
 48 {
 49     struct node *p;
 50     p=&root;   //从根节点开始搜索单词如果单词不存在则创建。
 51     int len=0;
 52     while(s[len]!='\0')
 53     {
 54         int index=s[len++]-'a'; //把小写字母a~z映射到数字的1~26,作为字典树的每一层的索引  
 55         
 56         if(!p->next[index])  //如果索引不存在构建索引。
 57             p->next[index]=new struct node;
 58         
 59         p=p->next[index];
 60     }
 61     
 62     if(p->flag)   //颜色单词存在,返回他的代号。
 63         return p->id;  
 64     else   
 65     {
 66         p->flag=true;
 67         p->id=++color;
 68         return p->id;  //不存在返回分配给颜色的编号。
 69     }
 70 }
 71 
 72 int main()  
 73 {
 74     int i,j;
 75     for(int k=1;k<=MAX;k++)   //初始化,每一个节点都是一个集合。
 76         ancestor[k]=k;     //对于只有一个节点的集合,x的祖先就是它本身。
 77     char a[11],b[11];
 78     while(scanf("%s%s",&a,&b) == 2)  
 79     {
 80     
 81         i=hash(a);
 82         j=hash(b);  //得到颜色编号。
 83         degree[i]++;
 84         degree[j]++;  //记录颜色出现的次数。
 85         union_set(i,j); //合并集合。
 86     }
 87     int s=find(1);     //若图为连通图,则s为所有结点的祖先    
 88                        //若图为非连通图,s为所有祖先中的其中一个祖先 
 89     int num=0;  //度数为奇数节点的个数。
 90     for(i=1;i<=color;i++)
 91     {
 92         if(degree[i]%2==1)
 93             num++;        
 94         if(num>2) //度数为奇数的结点数大于3,欧拉路必不存在   
 95         {
 96             printf("Impossible\n");
 97             return 0;
 98         }
 99 
100         if(find(i)!=s) //存在多个祖先,图为森林,不连通   
101         {
102             printf("Impossible\n");
103             return 0;
104         }
105     }
106 
107     if(num==1)  //度数为奇数的结点数等于1,欧拉路必不存在   
108         printf("Impossible\n");
109     else     //度数为奇数的结点数恰好等于2或不存在,存在欧拉路   
110         printf("Possible\n");
111     return 0;
112 }

 

posted on 2013-08-23 10:53  随风浪子的博客  阅读(148)  评论(0编辑  收藏  举报

导航