PKU2513 - 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.
 
解题报告和代码实现如下:
思路相当清晰
/* 解题报告: http://blog.csdn.net/clearriver/archive/2009/10/13/4665552.aspx 学会了基本的trie,并查集使用。 这道题大意是:已知有n根木棒,每个木棒有两种颜色表示两端, 问:能不能将所有的木棒连接成一条直线(连接处颜色相同)。 重点在与知道欧拉通路的概念和性质 可以考虑无向图的欧拉通路问题:将每种颜色看成图中的一个节点,木棒看作连接节点的边,于是判断两点: 1,每种颜色(节点)的度, G有欧拉通路的充分必要条件为:G 连通,G中只有两个奇度顶点(它们分别是欧拉通路的两个端点)。 2,是否为连通图 第一点可以通过trie树或则hash来解决。 第二点可以通过并查集来实现。 首先,每种颜色的度可以通过每条木棒的两端颜色的累积得到, 问题是,每种颜色都是字符串,怎么关联每种颜色和度呢? 最容易想到的是Hash,这肯定是可行的。例如degree [ hash(red) ]=5。表示颜色为红色的度为5。 但是,既然提示用trie树来做,那么trie树的节点的数据域就可以保存每种颜色的id(相当于分配的hash值, 可以通过一个全局变量自增产生),这样经过将每种颜色字符串插入到tree中以后, 通过trie树的search操作就能高效的获取每种颜色对应的id,每次插入一种颜色,为其产生一个id, 只需要注意相同颜色插入时的处理即可。 其次,判断无向图是否连通可以使用并查集来判定:经过n-1各union操作后,所有节点都在一个集合 (树形结构表示集合的话,即所有节点的父节点(集合代表)都一样)。由于每种颜色是由字符串来标示的, 每个集合保存颜色对应的唯一id。 通过上面两个步骤的判定,就可以得出结果。 */ #include <iostream> #include <cstring> #include <stdlib.h> #include <stdio.h> #define MAX 500004 using namespace std; char s1[15], s2[15]; //trie树 //用于记录每个color字符串对应的序号ID //每次执行insert操作都会返回一个ID,这个就是该字符串对应的ID // 同时还要一个数组,来使ID与颜色出现的个数对应上 //最后如果只有两个奇数的点才可以,否则输出impossible int degree[MAX]; struct TreeNode { int ID; bool term; TreeNode* next[27]; TreeNode() { ID = -1; term = false; int i; for(i = 0; i< 27; i++) next[i] = NULL; } }* root; int num = 0; int search(char* s, TreeNode* root) { TreeNode* p = root; if(p == NULL) return -1; int i = 0, l = strlen(s); for(i = 0; i< l; i++) { if(p->next[s[i] - 'a']== NULL) return -1; else p = p->next[s[i] - 'a']; } if(p->term == true) return p-> ID; else return -1; } int insert(char* s, TreeNode* root) { TreeNode* p = root; int t = search(s, root); if(t > 0) return t; int i = 0, l = strlen(s); for(; i< l; i++) { if(p->next[s[i] - 'a'] == NULL) p->next[s[i] - 'a'] = new TreeNode; p = p->next[s[i] - 'a']; } p->term = true; num ++; p->ID = num; return p->ID; } //并查集 //用于判断整张图的联通性,如果到最后边都输入完了之后,还是存在着多个集合 //说明并不是连通图,输出impossible。 int parent[MAX]; int rank[MAX]; void intial() { int i; for(i = 0; i < MAX; i++) { parent[i] = i; rank[i] = 1; degree[i] = 0; } } int find(int x) { if(parent[x] != x) parent[x] = find(parent[x]); return parent[x]; } void merge(int x, int y) { if(rank[x] > rank[y]) parent[y] = x; else if(rank[y] < rank[x]) parent[x] = y; else { rank[y] ++; parent[x] = y; } } int main() { //初始化trie树和并查集 root = new TreeNode; intial(); while(scanf("%s %s", s1, s2) != EOF) { //每次插入得到ID号,同时令degree[ID]++; int id1 = insert(s1, root); int id2 = insert(s2, root); degree[id1] ++; degree[id2] ++; //通过得到ID号,运用并查集,来求出组号GID int gid1 = find(id1); int gid2 = find(id2); if(gid1 != gid2) { merge(gid1, gid2); } } ////if the num of nodes whose degree is odd are more than 2 int i ,j; int noood = 0; for(i = 1; i<= num; i++) { if(degree[i] % 2 == 1) noood ++; if(noood > 2) { cout << "Impossible" << endl; return 0; } } ////if the g is joint. int gnum = parent[1]; for(i = 1; i<= num; i++) { if(gnum != parent[i]) { cout << "Impossible" << endl; return 0; } } cout << "Possible" << endl; return 0; }
 

你可能感兴趣的:(null,search,insert,merge,output,colors)