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 }