1. 程式人生 > >藍橋杯 國王的煩惱 (並查集)

藍橋杯 國王的煩惱 (並查集)

問題描述

C國由n個小島組成,為了方便小島之間聯絡,C國在小島間建立了m座大橋,每座大橋連線兩座小島。兩個小島間可能存在多座橋連線。然而,由於海水沖刷,有一些大橋面臨著不能使用的危險。

如果兩個小島間的所有大橋都不能使用,則這兩座小島就不能直接到達了。然而,只要這兩座小島的居民能通過其他的橋或者其他的小島互相到達,他們就會安然無事。但是,如果前一天兩個小島之間還有方法可以到達,後一天卻不能到達了,居民們就會一起抗議。

現在C國的國王已經知道了每座橋能使用的天數,超過這個天數就不能使用了。現在他想知道居民們會有多少天進行抗議。

輸入格式

輸入的第一行包含兩個整數n, m,分別表示小島的個數和橋的數量。

接下來m行,每行三個整數a, b, t,分別表示該座橋連線a號和b號兩個小島,能使用t天。小島的編號從1開始遞增。

輸出格式

輸出一個整數,表示居民們會抗議的天數。

樣例輸入

4 4
1 2 2
1 3 2
2 3 1
3 4 3

樣例輸出

2

思路

考慮用並查集來維護所有島嶼之間的連通性,我們可以對所有的邊按照使用期從大到小排序(反向思考),然後遍歷列舉。

在列舉的過程中,若一條邊的兩端不在同一個連通塊,則說明新增的這一個橋樑會引起群眾的抗議,此時 ans++

注意同一天的多次群眾抗議我們只統計一次。

AC 程式碼

#include <iostream>
#include <algorithm>
#include <string.h>
#include <queue>
#include <set>
#include <map>
#include <stack>
#define inf 0x7f7f7f
#define IO                       \
    ios::sync_with_stdio(false); \
    cin.tie(0);                  \
    cout
.tie(0); using namespace std; const int maxn = 1e6 + 10; typedef long long LL; int n,m; struct node{ int to; int from; int cost; int next; friend bool operator<(const node &x,const node &y){ return x.cost > y.cost; } }edge[maxn]; int head[maxn],tot; int fa[maxn],rk[maxn]; void init(){ memset(head,-1,sizeof(head)); tot = 0; } void addedge(int u,int v,int cost){ edge[tot].to = v; edge[tot].from = u; edge[tot].cost = cost; edge[tot].next = head[u]; head[u] = tot ++; } int find_set(int x){ if(x != fa[x]) fa[x] = find_set(fa[x]); return fa[x]; } bool union_set(int x,int y){ x = find_set(x); y = find_set(y); if(x==y)return false; if(rk[x]>rk[y]) fa[y] = x; else{ fa[x] = y; if(rk[x]==rk[y]) ++rk[y]; } return true; } void solve(){ memset(rk,0,sizeof(rk)); for(int i=1;i<maxn;i++) fa[i] = i; int ans = 0,now = -1; for(int i=0;i<tot;i++){ int from = edge[i].from; int to = edge[i].to; bool flag = union_set(from,to); if(flag && now != edge[i].cost){ ++ans; now = edge[i].cost; } } cout<<ans<<endl; } int main(){ IO; init(); cin>>n>>m; for(int i=0;i<m;i++){ int u,v,cost; cin>>u>>v>>cost; addedge(u,v,cost); } sort(edge,edge+tot); solve(); return 0; }