POJ2513——Colored Sticks(Trie树+欧拉回路+并查集)
Colored Sticks
Description
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?
Input
Input is a sequence of lines, 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 10 characters. There is no more than 250000 sticks.
Output
If the sticks can be aligned in the desired way, output a single line saying Possible, otherwise output Impossible.
Sample Input
blue red
red violet
cyan blue
blue magenta
magenta cyan
Sample Output
Possible
题目大意:
给定一些木条,木条的两头都有颜色,颜色相同的两根木条可以相连,问是否可以连成一条直线。
解题思路:
其实就是问是否可以构成欧拉路径。这里给出欧拉路径的定义。
若图G中存在这样一条路径,使得它恰通过G中每条边一次,则称该路径为欧拉路径。若该路径是一个圈,则称为欧拉(Euler)回路。(即一笔画问题)
存在欧拉路径的成分必要条件为:一个无向图存在欧拉回路,当且仅当该图只存在0或2个奇数入度数的顶点,且该图是连通图。
1)判断 奇数度数的个数
很好搞定,建立一个数组存放每个节点的入度,建图结束后遍历即可。
2)判断是否为连通图
使用并查集和路径压缩来做。若路径压缩之后每个点都有着相同的父节点(即每个点都有相同的祖先节点)。说明图连通。
Trie树的应用
由于该题的Node为字符串,建图的时候会比较困难。使用map映射会超时,所以使用Trie树来进行映射。具体实现请看代码备注。
Code:
1 /************************************************************************* 2 > File Name: poj2513.cpp 3 > Author: Enumz 4 > Mail: 369372123@qq.com 5 > Created Time: 2014年10月26日 星期日 20时16分17秒 6 ************************************************************************/ 7 8 #include<iostream> 9 #include<cstdio> 10 #include<cstdlib> 11 #include<string> 12 #include<cstring> 13 #include<list> 14 #include<queue> 15 #include<stack> 16 #include<map> 17 #include<set> 18 #include<algorithm> 19 #include<cmath> 20 #define MAXN 500001 21 using namespace std; 22 class TrieTree_Node 23 { 24 public: 25 bool flag; //判断是否为一个单词的叶子节点 26 int id; //为每一个单词分配一个id,相当于映射关系 27 TrieTree_Node *next[27]; 28 TrieTree_Node() 29 { 30 flag=0; 31 id=0; 32 memset(next,0,sizeof(next)); 33 } 34 }root; 35 int cnt=0; 36 int degree[MAXN]; //入度数组 37 int father[MAXN]; 38 int tree(char *s) 39 { 40 TrieTree_Node *p=&root; 41 int len=strlen(s); 42 for (int i=0;i<=len-1;i++) 43 { 44 int tmp=s[i]-'a'; 45 if (p->next[tmp]==NULL) 46 p->next[tmp]=new TrieTree_Node; 47 p=p->next[tmp]; 48 } 49 if (p->flag) //如果找到了该字符串,返回其ID 50 return p->id; 51 else //没有找到,就创建这个字符串,并标记叶子节点,分配ID 52 { 53 p->flag=1; 54 p->id=++cnt; 55 return p->id; 56 } 57 } 58 int find(int a) 59 { 60 if (father[a]!=a) 61 father[a]=find(father[a]); 62 return father[a]; 63 } 64 void join(int a,int b) 65 { 66 int fx=find(a),fy=find(b); 67 if (fx!=fy) 68 father[fx]=fy; 69 } 70 void init() 71 { 72 for (int i=0;i<MAXN;i++) //并查集初始化,每一个节点相当于一棵树 73 father[i]=i; 74 } 75 int main() 76 { 77 char a[11],b[11]; 78 init(); 79 while (scanf("%s %s",a,b)!=EOF) //无向图,两个Node的入度都要加 80 { 81 int i=tree(a); 82 int j=tree(b); 83 degree[i]++; 84 degree[j]++; 85 join(i,j); 86 } 87 bool ok=1; 88 int cnt_degree=0; 89 for (int i=1;i<=cnt;i++) 90 if (degree[i]%2!=0) cnt_degree++; 91 if (!(cnt_degree==0||cnt_degree==2)) 92 ok=0; 93 if (ok) 94 { 95 int tmp=find(1); 96 for (int i=2;i<=cnt;i++) 97 { 98 if (tmp!=find(i)) 99 ok=0; 100 } 101 } 102 if (ok) 103 cout<<"Possible"<<endl; 104 else 105 cout<<"Impossible"<<endl; 106 return 0; 107 }