1. 程式人生 > 其它 >新學一招 excel 的substring

新學一招 excel 的substring

並查集

基本介紹

資料結構一共分為四大類:集合、線性表、樹、圖,本文的資料結構就是第一種結構集合。

假設,一個集合即是一個小團伙,每個小團伙都有一個老大,每個團伙成員認識另一個成員,而團隊比較大不可能每個成員都互相認識吧,但是他們認識的人去找別的認識的人中最終都可以找到老大,這些人就構成了一個集合。那麼這個老大我們稱之為祖宗,每個人認識的那個人就是它的“父親“。

有點類似於樹的結構,這種尋找一般都是單向的,但是也可以增加資料域儲存”孩子“的資訊(一般不用)。類似於樹,我們就可以像操作樹那樣,用遞迴的方式實現尋找(當然也可以非遞迴)。

核心思想

一個節點一般包含兩個資訊域,一是自身的資訊,二是父親的資訊。

常見用法:定義一個數組,令陣列角標為資料的地址,單個數組元素的一個數據域就可以用來儲存“父親“的角標,以實現元素之間的連通。

判斷兩個元素是否在同一個集合,只需要不斷找“父親”指導找到“祖宗“,判斷“祖宗“是否相同即可。


圖 方框內是陣列角標,圓內是單個數組元素的資料域。圖中即為兩個集合。

程式碼實現

初始化

並查集在使用前一定要初始化,讓每個節點自己做自己的父親,因為最開始每個元素獨立自己是一個集合。

void init(int len) {
    for (int i = 0; i < len; i++)
        family[i].parent = i;
    
return; }

找“祖宗“

單純找

核心原理就是不斷的通過資料域的資訊去找“父親”,直到找到一個自己是自己“父親”的節點即“祖宗”。這個過程可以用遞迴也可以非遞迴實現。

1. 遞迴

int find(int aim) {
    if (family[aim].parent != aim)
        aim = find(family[aim].parent);
    return aim;
}

2. 非遞迴

int find(int x) {
    while (x != fa[x])
        x = fa[x];
    return x;
}


路徑壓縮

對於有些題目,實際路徑不會對解題有影響,就可以採用路徑壓縮,其目的就是減少find使用的時間。如上例子,“6”號位找祖宗要找三次,採用路徑壓縮只需要找一次即可。

int find(int x, int *fa){
    if(fa[x] != x) 
        fa[x] = find(fa[x], fa);//查詢+路徑壓縮,如果沒有祖先就回溯
    return fa[x];
}


合併

合併操作就是檢查兩個元素是否是同一個集合,如果不是就需要合併在同一個集合。對於誰做誰的父節點一般情況下沒有任何關係,因為並查集只是表述集合關係。但是在某些對路徑有要求的題目下,就要考慮誰做誰的父節點。

void merge(int a, int b, int *fa)
{
    a = find(a, fa);
    b = find(b, fa);
    if (a != b)
        fa[a] = b; // 如果兩個元素不相等就讓一個元素成為另一個元素的父節點
    return;
}


練習題

  https://www.luogu.com.cn/problem/P1551 P1551 親戚

  https://www.luogu.com.cn/problem/P1536 P1536 村村通

  https://www.luogu.com.cn/problem/P1525 P1525 [NOIP2010 提高組]關押罪(種類並查集)

  https://www.luogu.com.cn/problem/P1621 P1621 集合

  https://www.luogu.com.cn/problem/P1892 P1892 [BOI2003]團伙

  https://www.luogu.com.cn/problem/P1955 P1955 [NOI2015] 程式自動分析(這個有趣)

  https://www.luogu.com.cn/problem/P2814 P2814 家譜(這個簡單,不過字串處理一下)

  https://vjudge.net/contest/445444 這個並查集題單還是挺有趣的

  http://acm.hdu.edu.cn/showproblem.php?pid=3038 How Many Answers Are Wrong(這是一個帶權並查集,感興趣的可以試試)

我的題解

  P1551 親戚 - Kirk~~ - 部落格園 (cnblogs.com)

  P1536 村村通 - Kirk~~ - 部落格園 (cnblogs.com)

  P1525 [NOIP2010 提高組] 關押罪犯 - Kirk~~ - 部落格園 (cnblogs.com)

  P2814 家譜 - Kirk~~ - 部落格園 (cnblogs.com)