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 */

 

你可能感兴趣的:(trie)