1. 程式人生 > >POJ 2513 -- Colored Sticks

POJ 2513 -- Colored Sticks

des 並查集 mage ole 歐拉圖 聯通圖 rac 不能 cnblogs

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

The UofA Local 2000.10.14

題意:

給定一些木棒,木棒兩端都塗上顏色,求是否能將木棒首尾相接,連成一條直線,要求不同木棒相接的一邊必須是相同顏色的。

解題思路:

  將每一根火柴棍,看成一條邊,相同的顏色為同一個點,這樣我們可以把原問題轉化為,是否可以畫一條線,經過所有邊一次且僅一次。這就是歐拉圖,問是否存在歐拉通路(或者歐拉回路也可以)。

  歐拉通路也叫半歐拉圖,歐拉回路也叫歐拉圖。

  無向圖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 }

技術分享圖片

POJ 2513 -- Colored Sticks