“21 天好习惯”第一期-18

KD-Graph
思路:
按边权由小到大合并边的两个顶点,假设当前需要操作的边为 ( x , y , v a l ) {(x,y,val)} (x,y,val),则:
如果 x {x} x y {y} y已经在同一个组里了就不用继续合并了
如果 x {x} x y {y} y不在同一个组里,就将 x {x} x y {y} y所在的组合并,则 x {x} x y {y} y存在一条路径上的最大值就是 v a l {val} val,且找不到比其他的路径满足该路径上的最大值小于 v a l {val} val,因为 x {x} x y {y} y目前只有这一条路径(边),那么 D > = v a l {D>=val} D>=val

每一阶段取出同权值的所有边,将这些边的端点用并查集两两合并,待合并完这一阶段的全部边,并查集数量为 k {k} k,那么当前阶段合并边的权值就是答案,否则输出 − 1 {-1} 1。也就是说同权值的所有边要同时合并,因为未被合并的边的权值需要满足 v a l > D {val>D} val>D(因为题目要求 p {p} p q {q} q 之间不可能有任何路径满足该路径中的最大值小于或等于 D {D} D。)
code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 7,maxm=5e5+7;
int fa[maxn],n,m,k;
set<int>st;
unordered_map<int,int>mp;
vector<pair<int,int> >v[maxm];
inline int find(int x) {
	return x==fa[x]?x:(fa[x]=find(fa[x]));
}
inline void solve() {
	cin>>n>>m>>k;
	int cnt=n,ans=-1,x,y,tot(0);
	for(int i=1;i<=n;++i) fa[i]=i;
	for(auto i:st) v[mp[i]].clear();
	st.clear(); mp.clear();
	for(int i=1,c;i<=m;++i) {
		cin>>x>>y>>c;
		if(!mp.count(c)) mp[c]=++tot;
		st.insert(c);
		v[mp[c]].emplace_back(make_pair(x,y));
	}
	if(n==k) return printf("0\n"),void();
	for(auto i:st) {
		for(auto j:v[mp[i]]) {
			x=find(j.first),y=find(j.second);
			if(x!=y) {
				fa[y]=x; --cnt;
			}
		}
		if(cnt==k) return printf("%d\n",i),void();
		if(cnt<k) return printf("-1\n"),void();
	}
	printf("-1\n");
}
int main() {
//	freopen("1.txt","r",stdin);
//	freopen("brute.txt","w",stdout);
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);
    int T,n,m,k;
    cin>>T;
    while(T--) solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值