PKU2513 - Colored Sticks --一道很不错的题(结合了并查集的应用,字典树的应用,欧拉通路的原理)

PKU2513 - Colored Sticks --一道很不错的题(结合了并查集的应用,字典树的应用,欧拉通路的原理)

分类: 算法和数据结构学习   186人阅读  评论(0)  收藏  举报
insert colors search null merge output

 

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.
 
解题报告和代码实现如下:
思路相当清晰
[cpp]  view plain copy
  1. /* 
  2. 解题报告: http://blog.csdn.net/clearriver/archive/2009/10/13/4665552.aspx  
  3. 学会了基本的trie,并查集使用。 
  4.  
  5. 这道题大意是:已知有n根木棒,每个木棒有两种颜色表示两端, 
  6. 问:能不能将所有的木棒连接成一条直线(连接处颜色相同)。 
  7.  
  8. 重点在与知道欧拉通路的概念和性质  
  9. 可以考虑无向图的欧拉通路问题:将每种颜色看成图中的一个节点,木棒看作连接节点的边,于是判断两点: 
  10. 1,每种颜色(节点)的度, G有欧拉通路的充分必要条件为:G 连通,G中只有两个奇度顶点(它们分别是欧拉通路的两个端点)。 
  11. 2,是否为连通图 
  12.  
  13. 第一点可以通过trie树或则hash来解决。 
  14. 第二点可以通过并查集来实现。  
  15.  
  16. 首先,每种颜色的度可以通过每条木棒的两端颜色的累积得到, 
  17. 问题是,每种颜色都是字符串,怎么关联每种颜色和度呢? 
  18. 最容易想到的是Hash,这肯定是可行的。例如degree [ hash(red) ]=5。表示颜色为红色的度为5。 
  19. 但是,既然提示用trie树来做,那么trie树的节点的数据域就可以保存每种颜色的id(相当于分配的hash值, 
  20. 可以通过一个全局变量自增产生),这样经过将每种颜色字符串插入到tree中以后, 
  21. 通过trie树的search操作就能高效的获取每种颜色对应的id,每次插入一种颜色,为其产生一个id, 
  22. 只需要注意相同颜色插入时的处理即可。 
  23.  
  24. 其次,判断无向图是否连通可以使用并查集来判定:经过n-1各union操作后,所有节点都在一个集合 
  25. (树形结构表示集合的话,即所有节点的父节点(集合代表)都一样)。由于每种颜色是由字符串来标示的, 
  26. 每个集合保存颜色对应的唯一id。 
  27.  
  28. 通过上面两个步骤的判定,就可以得出结果。 
  29. */  
  30. #include <iostream>  
  31. #include <cstring>  
  32. #include <stdlib.h>  
  33. #include <stdio.h>  
  34. #define MAX 500004  
  35. using namespace std;  
  36. char s1[15], s2[15];  
  37.   
  38. //trie树   
  39. //用于记录每个color字符串对应的序号ID  
  40. //每次执行insert操作都会返回一个ID,这个就是该字符串对应的ID   
  41. // 同时还要一个数组,来使ID与颜色出现的个数对应上  
  42. //最后如果只有两个奇数的点才可以,否则输出impossible   
  43. int degree[MAX];  
  44. struct TreeNode  
  45. {  
  46.        int ID;  
  47.        bool term;  
  48.        TreeNode* next[27];  
  49.        TreeNode()  
  50.        {  
  51.             ID = -1;  
  52.             term = false;  
  53.             int i;  
  54.             for(i = 0; i< 27; i++)  
  55.                   next[i] = NULL;  
  56.        }  
  57. }* root;  
  58. int num = 0;  
  59.   
  60. int search(char* s, TreeNode* root)  
  61. {  
  62.     TreeNode* p = root;  
  63.     if(p == NULL) return -1;  
  64.     int i = 0, l = strlen(s);  
  65.     for(i = 0; i< l; i++)  
  66.     {  
  67.           if(p->next[s[i] - 'a']== NULL) return -1;  
  68.           else   p = p->next[s[i] - 'a'];  
  69.     }  
  70.     if(p->term == truereturn p-> ID;  
  71.     else return -1;  
  72. }  
  73.   
  74. int insert(char* s, TreeNode* root)  
  75. {  
  76.     TreeNode* p = root;  
  77.     int t = search(s, root);  
  78.     if(t > 0) return t;  
  79.       
  80.     int i = 0, l = strlen(s);  
  81.     for(; i< l; i++)  
  82.     {  
  83.           if(p->next[s[i] - 'a'] == NULL)  
  84.                 p->next[s[i] - 'a'] = new TreeNode;  
  85.           p = p->next[s[i] - 'a'];  
  86.     }  
  87.     p->term = true;  
  88.     num ++;  
  89.     p->ID = num;  
  90.     return p->ID;  
  91. }  
  92.   
  93.   
  94. //并查集  
  95. //用于判断整张图的联通性,如果到最后边都输入完了之后,还是存在着多个集合  
  96. //说明并不是连通图,输出impossible。   
  97. int parent[MAX];  
  98. int rank[MAX];  
  99.   
  100. void intial()  
  101. {  
  102.      int i;  
  103.      for(i = 0; i < MAX; i++)  
  104.      {    parent[i] = i;  
  105.           rank[i] = 1;  
  106.           degree[i] = 0;  
  107.      }  
  108. }   
  109.   
  110. int find(int x)  
  111. {  
  112.     if(parent[x] != x)  
  113.          parent[x] = find(parent[x]);  
  114.     return parent[x];  
  115. }  
  116.   
  117. void merge(int x, int y)  
  118. {  
  119.     if(rank[x] > rank[y])  
  120.         parent[y] = x;  
  121.     else if(rank[y] < rank[x])  
  122.         parent[x] = y;  
  123.     else  
  124.     {  
  125.         rank[y] ++;  
  126.         parent[x] = y;  
  127.     }  
  128. }   
  129.   
  130. int main()  
  131. {  
  132.     //初始化trie树和并查集   
  133.     root = new TreeNode;  
  134.     intial();  
  135.     while(scanf("%s %s", s1, s2) != EOF)  
  136.     {  
  137.            //每次插入得到ID号,同时令degree[ID]++;   
  138.            int id1 = insert(s1, root);  
  139.            int id2 = insert(s2, root);  
  140.            degree[id1] ++;  
  141.            degree[id2] ++;  
  142.              
  143.            //通过得到ID号,运用并查集,来求出组号GID   
  144.            int gid1 = find(id1);  
  145.            int gid2 = find(id2);  
  146.            if(gid1  != gid2)  
  147.            {  
  148.                  merge(gid1, gid2);  
  149.            }  
  150.     }  
  151.       
  152.     ////if the num of nodes whose degree is odd are more than 2  
  153.     int i ,j;  
  154.     int noood = 0;  
  155.     for(i = 1; i<= num; i++)  
  156.     {  
  157.   
  158.           if(degree[i] % 2 == 1) noood ++;  
  159.           if(noood > 2)  
  160.           {  
  161.                   cout << "Impossible" << endl;  
  162.                   return 0;  
  163.           }   
  164.     }  
  165.   
  166.     ////if the g is joint.  
  167.     int gnum = parent[1];  
  168.     for(i = 1; i<= num; i++)  
  169.     {  
  170.   
  171.           if(gnum != parent[i])  
  172.           {  
  173.                   cout << "Impossible" << endl;  
  174.                   return 0;  
  175.           }  
  176.     }  
  177.       
  178.     cout << "Possible" << endl;  
  179.       
  180.     return 0;  
  181. }  

你可能感兴趣的:(算法和数据结构学习)