POJ 2513 -- 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