POJ2513 Trie+並查集+歐拉迴路

來源:互聯網
上載者:User

題目大意:
給定一系列sticks,每個木棒的兩端都塗有顏色,判斷是否能夠找到將所有的木棒串連起來的方法,使相互串連的木棒的兩端的顏色是相同的?

分析:
畫圖分析可知,如果形成的圖能有一條路徑遍曆所有的邊並且不重複。則達到目的。不由想起歐拉迴路(從某個節點出發,不重複的遍曆所有路徑,回到原點,則為此圖的歐拉迴路)。而本題中並不要求回到原點。沒有歐拉迴路要求的苛刻。判斷無向圖是否有歐拉迴路的方法是圖中所有節點的度數為偶數。那麼對於此題來說,把條件放寬到圖中要麼沒有奇數度數的節點,要麼有兩個。原因大家自己畫畫就明白了。總結結論如下:
1.該圖必須是一個連通圖
2.該圖每個點的度數要麼全為偶數,要麼有且僅有兩個點的度數為奇數

解決方案:
1.找出奇數點度數的結點個數,可以用Map計算出每個節點的度數。效率太低。可以採用字典樹,尋找效率快,同時可以記錄某個串出現的度數。當然,我們的目的是計算奇數度數的結點個數,也就沒有必要把所有的串插入完之後再去遍曆一遍所有串的度數。巧妙地方法是,當我們插入某個串第奇數次時,加1,遍曆第偶數此時-1.那麼對於出現偶數次的串結果為0.最終我們只記錄了出現奇數次的串的個數。
2.為了保證圖的連通性,如果用傳統方法遍曆,效率必然很低。最好的辦法就是並查集了(http://www.cnblogs.com/cherish_yimi/archive/2009/10/11/1580839.html)抄錄如下:
並查集:(union-find sets)

一種簡單的用途廣泛的集合. 並查集是若干個不相交集合,能夠實現較快的合并和判斷元素所在集合的操作,應用很多,如其求無向圖的連通分量個數等。最完美的應用當屬:實現Kruskar演算法求最小產生樹。

I.並查集的精髓(即它的三種操作,結合實現代碼模板進行理解):
1、Make_Set(x) 把每一個元素初始化為一個集合
初始化後每一個元素的父親節點是它本身,每一個元素的祖先節點也是它本身(也可以根據情況而變)。
2、Find_Set(x) 尋找一個元素所在的集合
尋找一個元素所在的集合,其精髓是找到這個元素所在集合的祖先!這個才是並查集判斷和合并的最終依據。
判斷兩個元素是否屬於同一集合,只要看他們所在集合的祖先是否相同即可。
合并兩個集合,也是使一個集合的祖先成為另一個集合的祖先,具體見
3、Union(x,y) 合并x,y所在的兩個集合
合并兩個不相交集合操作很簡單:
利用Find_Set找到其中兩個集合的祖先,將一個集合的祖先指向另一個集合的祖先。

 

II.並查集的最佳化

1、Find_Set(x)時 路徑壓縮
尋找祖先時我們一般採用遞迴尋找,但是當元素很多亦或是整棵樹變為一條鏈時,每次Find_Set(x)都是O(n)的複雜度,有沒有辦法減小這個複雜度呢?
答案是肯定的,這就是路徑壓縮,即當我們經過"遞推"找到祖先節點後,"回溯"的時候順便將它的子孫節點都直接指向祖先,這樣以後再次Find_Set(x)時複雜度就變成O(1)了,如所示;可見,路徑壓縮方便了以後的尋找。
2、Union(x,y)時 按秩合并
即合并的時候將元素少的集合合并到元素多的集合中,這樣合并之後樹的高度會相對較小。

 

 

附上代碼:

#include<iostream>using namespace std;int num = 0;int num_of_odd = 0;//Triestruct Node{int id;//表示一個串,為了給並查集提供服務int cnt;//系統儲存了多少個本串Node* next[26];Node(){id = -1;cnt = 0;int i = 0;for(i = 0; i < 26; i++){next[i] = NULL;}}};Node* root = new Node();int insert(char* str){Node* p = root;int i = 0;for(i = 0; i < strlen(str); i++){if(p->next[str[i] - 'a'] == NULL){Node *q = new Node();p->next[str[i] - 'a'] = q;}p = p->next[str[i] - 'a'];}p->cnt++;if(p->cnt & 1){num_of_odd++;} else {num_of_odd--;}if(-1 == p->id){p->id = ++num;}return p->id;}//並查集int rank[500002] = {0};int parent[500002] = {0};int find_set(int x) {    if (0 == parent[x]) {       return -1;    }    if (parent[x] != x) {        parent[x] = find_set(parent[x]);    }    return parent[x];}void make_set(int x) {    if (find_set(x) == -1) {        parent[x] = x;        rank[x] == 0;    }}void union_set(int x, int y) {    x = find_set(x);    y = find_set(y);    if (x == y) return;    if (rank[x] == rank[y]) {        parent[x] = y;        rank[y]++;    } else if (rank[x] < rank[y]) {        parent[x] = y;    } else {        parent[y] = x;    }}int main(){//freopen("2513.txt", "r", stdin);char str1[11];char str2[11];while(scanf("%s", str1) != EOF){scanf("%s", str2);int a = insert(str1);int b = insert(str2);make_set(a);make_set(b);union_set(a, b);}if(num_of_odd != 0 && num_of_odd != 2){cout << "Impossible" << endl;return 0;}int i = 0;int temp = find_set(1);for(i = 2; i <= num; i++){if(find_set(i) != temp){break;}}if(i <= num){cout << "Impossible" << endl;return 0;}cout << "Possible" << endl;return 0;}

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.