【luogu/並查集】修復公路(查看並查集是否包含所有元素)

問題描述:

題目背景

AAA地區在地震過後,連接所有村莊的公路都造成了損壞而無法通車。政府派人修復這些公路。

題目描述

給出A地區的村莊數NNN,和公路數MMM,公路是雙向的。並告訴你每條公路的連着哪兩個村莊,並告訴你什麼時候能修完這條公路。問最早什麼時候任意兩個村莊能夠通車,即最早什麼時候任意兩條村莊都存在至少一條修復完成的道路(可以由多條公路連成一條道路)

輸入格式

第111行兩個正整數N,MN,MN,M

下面MMM行,每行333個正整數x,y,tx, y, tx,y,t,告訴你這條公路連着x,yx,yx,y兩個村莊,在時間t時能修復完成這條公路。

輸出格式

如果全部公路修復完畢仍然存在兩個村莊無法通車,則輸出−1-1−1,否則輸出最早什麼時候任意兩個村莊能夠通車。

輸入輸出樣例

輸入 #1

4 4
1 2 6
1 3 4
1 4 5
4 2 3

輸出 #1

5

說明/提示

N≤1000,M≤100000N \le 1000,M \le 100000N≤1000,M≤100000

x≤N,y≤N,t≤100000x \le N,y \le N,t \le 100000x≤N,y≤N,t≤100000

 

基本思路:

利用並查集合並集合。

這裏除第一行後的每一行都是關於邊的信息,每一條邊連接哪兩個節點,這種題目我們就可以用並查集來做。

唯一的問題就是如何判斷我們的集合是否已經包含全部的元素。

這裏我的解決方法就是引入一個記錄根節點所含元素個數的變量,如果他的個數==n,那麼就說明已經完全連同了。

 

AC代碼:

#include<bits/stdc++.h>
using namespace std;

struct Road {
// 兩個村莊的編號以及修復路的時間
  int x;
  int y;
  int t;

  Road() = default;
  Road(int _x, int _y, int _t) :
    x(_x), y(_y), t(_t) {}
};

constexpr int kNum = 1005;
int p[kNum];    // 存放父親節點
int r[kNum];    // 存放集合的秩
int s[kNum]; // 存放集合的元素個數
// 這裏竟然也要提供構造函數
vector<Road> road;    // 這裏的容器好像就是某種特定類型的容器

void Initialize() {
  for (int i = 0; i < kNum; ++i) {
    p[i] = i; 
    r[i] = s[i] = 1;
  }
}

int Find(int x) {
// 根據元素找相應集合的根節點
  // 找到根節點了
  if (x == p[x]) {
    return x;
  }
  return p[x] = Find(p[x]);
}

void Union(int x, int y) {
  int p_x = Find(x);
  int p_y = Find(y);
  // 兩個元素位於同一個集合中
  if (p_x == p_y) {
    return;
  }
  // 兩個元素不在同一個集合中
  if (r[p_x] > r[p_y]) {
    p[p_y] = p_x;
    s[p_x] += s[p_y];
  } else {
    if (r[p_x] == r[p_y]) {
      ++r[p_y];
    }
    p[p_x] = p_y;
    s[p_y] += s[p_x];
  }
}

int main() {
  Initialize();
  int n, m;
  cin >> n >> m;
  for (int i = 0; i < m; ++i) {
    int q, w, e;
    cin >> q >> w >> e;
    road.push_back(Road(q, w, e));
  }
  sort(road.begin(), road.end(), [] (Road x, Road y) { return x.t < y.t; });
  for (int i = 0; i < m; ++i) {
    Union(road[i].x, road[i].y);
    if (s[Find(road[i].x)] == n) {
      cout << road[i].t << endl;
      return 0;
    }
  }
  cout << "-1\n";
  return 0;
}

其他經驗:

  1.  並查集在使用之前要進行初始化
  2. 自定義類的數組,由於不知道可能要放什麼元素,所以一般不會進行初始化,這時候就要求你提供默認構造函數了。
  3. 要明白自己是使用vector還是使用array,後者可能由於不知道會有幾個元素,所以預先開闢很多空間——這樣就會導致很多沒有用的元素會混到我們所需要元素的操作中(比如對數組進行sort排序,那隻能begin, end, 但這個顯然不對);vector使用效率可能比array的效率要稍微低一點(開闢新的空間啥的),但是就沒有這樣的困擾
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章