POJ 2513 -- Colored Sticks

Colored Sticks
Time Limit: 5000MS   Memory Limit: 128000K
Total Submissions: 38355   Accepted: 10044

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

Hint

Huge input,scanf is recommended.

Source

 

题意:

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

 

解题思路:

  将每一根火柴棍,看成一条边,相同的颜色为同一个点,这样我们可以把原问题转化为,是否可以画一条线,经过所有边一次且仅一次。这就是欧拉图,问是否存在欧拉通路(或者欧拉回路也可以)。

  欧拉通路也叫半欧拉图,欧拉回路也叫欧拉图。

  无向图G是半欧拉图 当且仅当  1.G是连通的  2.恰有两个奇度定点

  无向图G是欧拉图 当且仅当  1.G是连通的  2.没有奇度定点

  ps:或许与人会注意到,每次插入的是一条边,每条边上有两个点,那么是否可以这样想:如果有两条边有颜色相同的点,那么就把这两个点粘起来,形成一条新边,这样一直插入所有边,如果木棍能够连接成一条直线,那么最后应该只剩下两个端点,如果大于两个端点,就不能连成一条直线。因为每次输入的是一条边,所以输入的两个点一定是连通的,将它与另一个边相接,新生成的木棍一定也是连通的,所以这种不像是判断欧拉图那样一个点一个点的输入,是否可以不判断连通性?答案是不可以,因为木棍可能两端点同色,这样,木棍在我们的模拟中,就会退化成一个点,所以这个问题又退化成了单点输入的欧拉图问题。

  所以我们首先判断奇度定点的个数。将颜色string与出现次数int联系起来

  如果使用map的话会超时,虽然STL的map是基于hash的基础上,但并不高效

  这里使用字典树为每个字符串一个编号。

  关于字典树=》浅谈Trie树(字典树)

  判断是否联通肯定就是用并查集了。使用并查集时必须压缩路径,前几次搜索某个结点k的祖先时,在不断通过父亲结点寻找祖先结点时,顺便把从k到最终祖先结点S中经过的所有结点的祖先都指向S,那么以后的搜索就能把时间降低到O(1)

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 using namespace std;
 5 const int large = 250000*2;//最多有250000*2个结点
 6 int color=0;//记录当前颜色的编号
 7 int Count[large+1] = {0};//第id个结点出现的次数
 8 int ancestor[large+1];//第id个结点的祖先
 9 
10 class HashTable{
11 public:
12     int id;
13     HashTable *next[27];//存储子树的颜色
14     HashTable()//初始化
15     {
16         id = 0;
17         memset(next,0,sizeof(next));
18     }
19 }root;//根节点root
20 
21 int hash(char *a)
22 {
23     HashTable *temp = &root;//从根节点开始查找
24     int i=0;
25     while(a[i] != '\0')
26     {
27         if(!temp->next[a[i]-'a'])//索引不存在
28             temp->next[a[i]-'a'] = new HashTable;//创建索引
29         temp = temp->next[a[i]-'a'];
30         i++;
31     }
32     if(temp->id)//颜色单词已存在
33         return temp->id;//返回其编号
34     else{
35         temp->id = ++color;
36         return temp->id;
37     }
38 }
39 
40 int find(int i)
41 {
42     if(ancestor[i] != i)
43         ancestor[i]=find(ancestor[i]);//路径压缩
44     return ancestor[i];
45 }
46 
47 void union_anc(int i,int j)
48 {
49     int pi = find(i);
50     int pj = find(j);
51     ancestor[pj] = pi;//使i的祖先作为j的祖先
52     return;
53 }
54 
55 int main()
56 {
57     for(int i=0;i<=large;i++)
58     {
59         ancestor[i] = i;//初始化每个颜色id的祖先为自己
60     }
61     char a[20],b[20];
62     while(cin>>a>>b)
63     {
64         int i = hash(a);//得到颜色编号
65         int j = hash(b);
66         ///计数增加
67         Count[i]++;
68         Count[j]++;
69 
70         ///将i和j的祖先合并
71         union_anc(i,j);
72     }
73     int s = find(1);//若图为联通图,则s为所有结点的共同祖先
74                     //若图为非连通图,s为所有祖先中的其中一个祖先
75     int num = 0;//度数为奇数的节点个数
76     for(int i=1;i<=color;i++)
77     {
78         if(Count[i]%2)//度为奇数
79             num++;
80         if(num>=3)
81         {
82             cout<<"Impossible"<<endl;
83             return 0;
84         }
85         if(find(i)!=s)
86         {
87             cout<<"Impossible"<<endl;
88             return 0;
89         }
90     }
91     if(num == 1)
92         cout<<"Impossible"<<endl;
93     else
94         cout<<"Possible"<<endl;
95 
96     return 0;
97 }

 

 

posted @ 2018-02-13 10:16  卉卉卉大爷  阅读(195)  评论(0编辑  收藏  举报