藍橋杯 國王的煩惱 (並查集)
阿新 • • 發佈:2019-02-02
問題描述
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;
}