poj2513_trie_并查集_欧拉路

题意:给定一些木棒,木棒两端都涂上颜色,求是否能将木棒首尾相接,连成一条直线,要求不同木棒相接的一边必须是相同颜色的。

分析:

参考http://blog.csdn.net/lyy289065406/article/details/6647445

可以用图论中欧拉路的知识来解这道题,首先可以把木棒两端看成节点,把木棒看成边,这样相同的颜色就是同一个节点

问题便转化为:给定一个图,是否存在“一笔画”经过涂中每一点,以及经过每一边一次。这样就是求图中是否存在欧拉路Euler-Path。

由图论知识可以知道,无向图存在欧拉路的充要条件为:

①     图是连通的;

②     所有节点的度为偶数,或者有且只有两个度为奇数的节点。

图的连通性可以通过并查集来做,但是首先得hash到int型,但是使用map会超时。因此使用了trie树,这也是我第一次用trie来hash。所以这个题挺综合的。用到了三个知识呀。

代码:

View Code
  1 #include <iostream>
  2 #include <string.h>
  3 #include <stdio.h>
  4 using namespace std;
  5 //79372K 1157MS
  6 //trie+并查集+欧拉路径
  7 const int maxnum=500010;
  8 int degree[maxnum],parent[maxnum],rank[maxnum];
  9 int n=1;
 10 struct node
 11 {
 12     int id;
 13     bool use;
 14     node *next[27];
 15     node()
 16     {
 17         id=0;
 18         use=false;
 19         int i;
 20         for(i=0;i<27;i++)
 21             next[i]=NULL;
 22     }
 23 };
 24 node *root;
 25 
 26 int hash(char *str)
 27 {
 28     node *p=root;
 29     int k;
 30     while(*str!=0)
 31     {
 32         k=*str-'a';
 33         if(p->next[k]==NULL)
 34             p->next[k]=new node();
 35         p=p->next[k];
 36         str++;
 37     }
 38     if(!p->use)
 39     {
 40         p->id=n;
 41         n++;
 42         p->use=true;
 43         return p->id;
 44     }
 45     else
 46         return p->id;
 47 }
 48 
 49 int find(int u)
 50 {
 51     if(u!=parent[u])
 52         parent[u]=find(parent[u]);
 53     return parent[u];
 54 }
 55 
 56 void Union(int i,int j)
 57 {
 58     if(rank[i]<rank[j])
 59         parent[i]=j;
 60     else
 61     {
 62         parent[j]=i;
 63         if(rank[i]==rank[j])
 64             i++;
 65     }
 66 }
 67 
 68 int main()
 69 {
 70     char a[15],b[15];
 71     int i;
 72     root=new node();
 73     for(i=1;i<maxnum;i++)
 74         parent[i]=i;
 75     while(scanf("%s%s",a,b)!=EOF)
 76     {
 77         int k=hash(a);
 78         int l=hash(b);
 79         degree[k]++;
 80         degree[l]++;
 81 
 82         int p=find(k);
 83         int q=find(l);
 84         if(p!=q)
 85             Union(p,q);
 86     }
 87     int t=find(1);
 88     int num=0;  //度数为奇数的结点个数
 89     for(i=1;i<n;i++)
 90     {
 91         if(find(i)!=t)//存在多个祖先,图为森林,不连通
 92         {
 93             printf("Impossible\n");
 94             return 0;
 95         }
 96         if(degree[i]%2==1)
 97             num++;
 98         if(num>2)  //度数为奇数的结点数大于3,欧拉路必不存在
 99         {
100             printf("Impossible\n");
101             return 0;
102         }
103     }
104     if(num==1)  //度数为奇数的结点数等于1,欧拉路必不存在
105         printf("Impossible\n");
106     else   //度数为奇数的结点数恰好等于2或不存在,存在欧拉路
107         printf("Possible\n");
108     return 0;
109 }
110 
111 /*
112 blue red
113 red violet
114 cyan blue
115 blue magenta
116 magenta cyan
117 */

 

posted @ 2012-08-24 12:49  pushing my way  阅读(699)  评论(0编辑  收藏  举报