並查集_模版

来源:https://www.cnblogs.com/normaldisk/archive/2018/07/18/9282719.html
-Advertisement-
Play Games

並查集 並查集,在一些有N個元素的集合應用問題中,我們通常是在開始時讓每個元素構成一個單元素的集合,然後按一定順序將屬於同一組的元素所在的集合合併,其間要反覆查找一個元素在哪個集合中。這一類問題近幾年來反覆出現在信息學的國際國內賽題中,其特點是看似並不複雜,但數據量極大,若用正常的數據結構來描述的話 ...


並查集

  並查集,在一些有N個元素的集合應用問題中,我們通常是在開始時讓每個元素構成一個單元素的集合,然後按一定順序將屬於同一組的元素所在的集合合併,其間要反覆查找一個元素在哪個集合中。這一類問題近幾年來反覆出現在信息學的國際國內賽題中,其特點是看似並不複雜,但數據量極大,若用正常的數據結構來描述的話,往往在空間上過大,電腦無法承受;即使在空間上勉強通過,運行的時間複雜度也極高,根本就不可能在比賽規定的運行時間(1~3秒)內計算出試題需要的結果,只能用並查集來描述。

  並查集是一種樹型的數據結構,用於處理一些不相交集合的合併及查詢問題。常常在使用中以森林來表示。

例題:

輸入格式:

第一行包含兩個整數N、M,表示共有N個元素和M個操作。
接下來M行,每行包含三個整數Zi、Xi、Yi
當Zi=1時,將Xi與Yi所在的集合合併
當Zi=2時,輸出Xi與Yi是否在同一集合內,是的話輸出Y;否則話輸出N

輸出格式:

如上,對於每一個Zi=2的操作,都有一行輸出,每行包含一個大寫字母,為Y或者N

模版代碼:

#include<cstdio>
#include<iostream>
using namespace std;
int a1,a2,a3,f[200001],n,m;

int getf(int o) {
    if (f[o]==o) return o;
    else return f[o]=getf(f[o]);
}

void make(int v, int u) {
    int t1,t2;
    t1=getf(v);
    t2=getf(u);
    if (t1!=t2) f[t2]=t1;
    return; 
}
void find(int v,int u) {
    int t1,t2;
    t1=getf(v);
    t2=getf(u);
    if (t1==t2) printf("Y\n");
    else printf("N\n");
}
int main() {
    scanf("%d%d", &n, &m);
    for (int i=1; i<=n; i++) f[i]=i;
    for (int i=1; i<=m; i++) {
        scanf("%d%d%d", &a1, &a2, &a3);
        if (a1==1) make(a2, a3);
        else find(a2, a3);
    }
    return 0;
}

主要應用類型:
1.團夥問題(搭橋問題,修路問題):求連通塊
2.最小生成樹(kruskal)
3.L最近公共祖先(LCA)中的Tarjan
並查集的合併過程:(路徑壓縮)

int  find(int x) {
    if(fa[x]!=x)  fa[x]=find(fa[x]);
    return fa[x]; 
     //或  return x==fa[x] ? x : fa[x]=find(fa[x]); 
}

因此,並查集在查詢是否在同一集合時十分快捷

if(fa[a]==fa[b]) {
    ...
}

與並查集相對的,可以有一種拆分集:

例題:

題目描述:
維護一個數據結構支持下列兩個操作:
-刪除某條邊,表示為”D x”,即為刪除第x條邊
-查詢兩點是否屬於一個集合,表示為”Q a b”,即為查詢節點a與節點b是否在一個集合內,若在同一個集合內,輸出”Yes”,否則輸出”No”(輸出不包括引號)

輸入:
第一行包括三個正整數數據結構中節點的個數n,邊數m,操作數q
接下來的m行每行包括兩個正整數u,v,表示節點u與節點v在同一個集合里
再接下來的q行每行包括一個格式如題描述操作
輸出:
對於每一個查詢,輸出包括一行,表示查詢結果,即如果兩點屬於同一個集合輸出”Yes”,否則輸出”No”。

實際上,將刪除操作存下來,反向就可以建立並查集,將答案倒序輸出即可

代碼:

#include<cstdio>
#include<cstring>
#include<iostream>
#define CL(X,N) memset(X, N, sizeof(X))
#define LL long long
using namespace std;
const int maxn=1e5+10;
int n, m, q;
int a[maxn], b[maxn];
int u[maxn], v[maxn], f[maxn];
char op[maxn];
bool del_state[maxn];

int _find(int x) {
    return x==f[x] ? x : f[x]=_find(f[x]);
}

void merge(int x, int y) {
    f[_find(y)]=_find(x);
    return ;
}

int main() {
    scanf("%d%d%d", &n, &m, &q);
    for(int i=1; i<=n; i++) f[i]=i;
    for(int i=1; i<=m; i++) scanf("%d%d", a+i, b+i);
    for(int i=1; i<=q; i++) {
        char cmd[2];
        scanf("%s", cmd);
        op[i]=cmd[0];/*存操作符*/ 
        switch(cmd[0]) {
            case 'D' : {
                scanf("%d", u+i);
                del_state[u[i]]=1;/*是否刪除*/
                break;
            }
            case 'Q' : {
                scanf("%d%d", u+i, v+i);
                break;
            }
            default : break;
        }
    }
    for(int i=1; i<=m; i++) if(!del_state[i]) merge(a[i], b[i]);
    /*將沒被刪除的邊加入集合*/
    int ans[maxn], cnt=0;
    for(int i=q; i>0; i--) {
        if(op[i]=='Q') {
            if(_find(u[i])==_find(v[i])) ans[cnt++]=1;
            else ans[cnt++]=0;/*正向存答案*/
        }
        else merge(a[u[i]], b[u[i]]);
    }
    for(int i=cnt-1; i>=0; i--) printf(ans[i] ? "Yes\n" : "No\n");/*倒序輸出答案*/
    return 0;
}

如果有多種歸屬的情況,可以考慮建立多倍並查集

例題:

洛谷P2024 食物鏈

洛谷上 Sooke (dalao)的講解很詳細,此處就不再多說(才不是我懶得寫了)這道題比較巧妙的地方在於判斷相關性,建議一做。

至於Tarjan,這個演算法主要還是與LCA有關,並查集只是中途用來判斷兩點是否在同一棵子樹,不過對並查集的利用還是很巧妙的

下麵給出部分Tarjan的模版代碼:

void work(int fa,int son) {    //這裡是Tarjan部分
    f[son]=son;
    for(int i=head[son];i;i=edge[i].net) {
        int to=edge[i].to;
        if(to==fa) continue;
        dis[to]=dis[son]+edge[i].c;    /*更新深度*/
        work(son,to);
        f[to]=son;
    }
    ...
return
; }

由於遞歸過程中,work(son, to) 比 f[to]=son先執行,因此可以看做這是在樹上自底向上將節點加入並查集

". . ." 部分可以是對深度或距離的更新查詢,但由於查詢順序不一定於答案順序相同(work(fa, son) 函數像先序遍歷),就需要先存再輸出,不過整個演算法的時間複雜度是十分優秀的(因為只查詢了一遍)

對於答案順序的具體原因這裡不做更多說明,希望瞭解的還請瀏覽其他博客

(最後好像水了點)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 原創 The Suspects Time Limit: 1000MS Memory Limit: 20000K Total Submissions: 48698 Accepted: 23286 Description Severe acute respiratory syndrome (SARS), ...
  • 1. 學習計劃 第二天:商品列表功能實現 1、服務中間件dubbo 2、工程改造為基於soa架構 3、商品列表查詢功能實現。 2. 將工程改造為SOA架構 2.1. 分析 由於宜立方商城是基於soa的架構,表現層和服務層是不同的工程。所以要實現商品列表查詢需要兩個系統之間進行通信。 如何實現遠程通信 ...
  • provider pom 連接註冊器register需要applicationContext需要web.xml載入配置文件監聽器 註冊 介面 實現類 註意這個@Service是dubbo的Service 右擊maven項目run as選maven build.. 輸入tomcat7:run 啟動這個 ...
  • w2 16、第二周-第02章節-Python3.5-模塊初識 sys模塊 sys.path sys.argv os模塊 os.system os.popen os.mkdir 17、第二周-第03章節-Python3.5-模塊初識2 18、第二周-第04章節-Python3.5-pyc是什麼 19、 ...
  • http://www.cnblogs.com/baixl/p/4170599.html ...
  • gets()函數 因為用gets函數輸入數組時,只知道數組開始處,不知道數組有多少個元素,輸入字元過長,會導致緩衝區溢出,多餘字元可能占用未使用的記憶體,也可能擦掉程式中的其他數據,後續用fgets函數代替。 fgets函數 一小段代碼舉例: (1) fgets函數一次讀入10 - 1個字元,如果少於 ...
  •   傳送文件描述符是高併發網路服務編程的一種常見實現方式。 "Nebula" 高性能通用網路框架即採用了UNIX域套接字傳遞文件描述符設計和實現。本文詳細說明一下傳送文件描述符的應用。 1. TCP伺服器程式設計範式   開發一個伺服器程式,有較多的的程式設計 ...
  • 在學習Celery之前,我先簡單的去瞭解了一下什麼是生產者消費者模式。 生產者消費者模式 在實際的軟體開發過程中,經常會碰到如下場景:某個模塊負責產生數據,這些數據由另一個模塊來負責處理(此處的模塊是廣義的,可以是類、函數、線程、進程等)。產生數據的模塊,就形象地稱為生產者;而處理數據的模塊,就稱為 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...