HDU 1232——暢通工程 並查集入門題
阿新 • • 發佈:2018-12-12
- 題意 :給定你n個村莊以及m條路,每條路連線兩個村莊,求還需要最少多少條路使得任意兩個村莊之間互相可以到達(直接間接都可以)。
- 思路 : 這是一道並查集經典的入門題,可以看這些村莊有多少個連通分量,然後連通分量的個數- 1即為答案 如圖所示,這是第一個樣例,節點1 3 4即為一個連通分量,2為一個連通分量,要想讓任意兩個村莊都能到達,只需要2 和 1 3 4任意一點連線即可。(圖中的方向只是為了表示1 到 3 的路和3 到1的路不同,不過走起來是沒有方向的。)
- 程式碼 :
#include "bits/stdc++.h" using namespace std; #define mem(a,b) memset(a,b,sizeof(a)) #define fori(i,l,u) for(int i = l;i < u;i++) #define forj(j,l,u) for(int j = l;j < u;j++) #define pb push_back #define mk make_pair #define F first #define S second typedef long long ll; typedef pair<string, int > ps; typedef pair<int, int> pi; typedef vector<int> vi; typedef vector<ll> vl; typedef vector<pi> vpi; const int maxn = 1e6 + 6; ll N; ll M; ll u,v; ll node[maxn]; ll ans = 0,visit[maxn]; ll find(ll x){ //尋找根節點座標,因為init裡初始 i = node[i] if (x == node[x]) { return x; } return find(node[x]); } void Unite(ll x,ll y){ //合併集合 x = find(x); y = find(y); if (x == y) { return; } node[x] = y; } bool same(ll x,ll y){ //判斷是不是同一集合,判斷根節點的下標 return find(x) == find(y); } void init(){ //初始化 mem(visit,0); fori(i, 1, N+1){ node[i] = i; } } //以上都是並查集的板子 int main() { // freopen("1.txt", "r", stdin); while(~scanf("%lld%lld",&N,&M) && N){ init(); ans = 0; fori(i, 0, M){ scanf("%lld%lld",&u,&v); if (!same(u, v)) { //判斷是不是同一個連通分量 Unite(u, v); } } fori(i, 1, N+1){ if (node[i] == i) { //判斷有多少個連通分量 ans ++; } } ans -= 1; printf("%lld\n",ans); } return 0; }
- 遇到的問題 :這是第一道並查集的題,只需要把板子寫上,有些理解就能做出來。最後,一定要註釋掉 freopen!!!不然聽取WA聲一片。