天天看點

hdu1232(并查集)

關于并查集,最主要的是是這樣的一張圖

hdu1232(并查集)

也就是維護與查詢集合。

而為了加快查詢查詢,可以進行的就是将上圖的左集合變換為右集合,稱之為壓縮路徑。

因為我們隻想知道該元素是否屬于某集合,是以路徑壓縮雖然改變了元素的前驅,但是保留的是父節點,也就是頂點。

我們考慮單鍊的情況,如果存在單鍊如圖

hdu1232(并查集)

那麼通過優化,可得

hdu1232(并查集)

如果元素多了之後,查詢兩元素是否屬于同一集合,則可以将O(n)的複雜度降為O(1),這樣對于多次查詢的情況,可以極大提高效率。

以HDU1232為例,代碼如下

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int pre[1050];

int Find(int x) //已優化
{
    int r = x;
    while(pre[r] != r)
        r = pre[r];
    int i = x, j;
    while (i != r)
    {
        j = pre[i];
        pre[i] = r;
        i = j;
    }
    return r;
}

void Join(int x, int y)
{
    int fx = Find(x), fy = Find(y);
    if (fx != fy)
        pre[fx] = fy;
}

int main()
{
    int n, m;
    while (scanf("%d%d", &n, &m) && n)
    {
        for (int i = 1; i <= n; i++)
            pre[i] = i;
        for (int i = 0; i < m; i++)
        {
            int s, e;
            scanf("%d%d", &s, &e);
            Join(s, e);
        }
        int ans = 0;
        for (int i = 1; i <= n; i++)
            if (pre[i] == i)
                ans++;
        printf("%d\n", ans - 1);
    }
    return 0;
}
           

其中

Find函數為查詢元素x,并傳回父元素r。代碼裡的是已經進行了路徑壓縮後的查詢函數。

Join函數為合并元素,将x與y合并,置入一個集合。

集合的初始化我寫到了main函數裡,是這兩句代碼

for (int i = 1; i <= n; i++)
            pre[i] = i;
           

可以單獨提出來寫成一個初始化函數。