【ETOJ P1074】能不能走到捏 题解(Kruskal算法+并查集+启发式合并)

题目描述

给定一个 n n n 个点, m m m 条边的无向图,每条边有一个权值。

问是否存在一条从 1 到 n n n 的路径使得路径上的权值的最大值最小,求出这个最大值。

如果 1 号点和 n n n 号点不连通,则输出 -1。

注意:请勿采用递归形式的DFS,谨防爆栈。

输入格式

第一行两个整数 n n n, m m m ( 2 ≤ n ≤ 2 × 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 ) (2 \leq n \leq 2 \times 10^5, 1 \leq m \leq 2 \times 10^5) (2n2×105,1m2×105)

接下来 m m m 行,每行三个整数 u i , v i , w i u_i,v_i,w_i ui,vi,wi 表示在 u i u_i ui v i v_i vi 之间存在一条权值为 w i w_i wi 的无向边。 ( 1 ≤ u i , v i ≤ n , 0 ≤ w i ≤ 1 0 4 ) (1 \leq u_i, v_i \leq n, 0 \leq w_i \leq 10^4) (1ui,vin,0wi104)

输出格式

一个整数表示答案。

样例输入1

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

样例输出1

2

样例输入2

3 2
1 2 1
1 2 5

样例输出2

-1

思路

首先,定义一个并查集的数据结构,其中pre[N]表示每个节点的父节点,sz[N]表示以每个节点为根的子树的大小。init函数用于初始化并查集,root函数用于查找一个节点的根节点,merge函数用于合并两个节点所在的集合,check函数用于检查两个节点是否在同一个集合中。

在主函数中,首先读取节点和边的数量,然后初始化并查集。接着,读取每条边的信息,并将其添加到edge向量中。然后,使用sort函数将edge向量中的边按照权值从小到大排序。

接下来,遍历排序后的边,尝试合并每条边的两个端点。如果1号点和n号点在同一个集合中,那么就找到了一条从1号点到n号点的路径,路径上的权值的最大值最小,然后输出这个最大值。

如果遍历完所有的边后,1号点和n号点还不在同一个集合中,那么就输出-1,表示1号点和n号点不连通。


AC代码

#include 
#include 
#include 
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;

const int N = 1e6 + 7;

struct Sedge {
	int u, v, w;
};

int n, m;
int pre[N], sz[N];
vector<Sedge> edge;

void init(int n) {
	for (int i = 1; i <= n; i++) {
		pre[i] = i;
		sz[i] = 1;
	}
}

int root(int x) {
	int i = x;
	while (pre[i] != i) {
		i = pre[i];
	}
	return i;
}

void merge(int x, int y) {
	int rx = root(x);
	int ry = root(y);
	if (rx == ry) {
		return;
	}
	// cout << x << " " << y << endl;
	if (sz[rx] > sz[ry]) {
		swap(rx, ry);
	}
	pre[rx] = ry;
	sz[ry] += sz[rx];
}

bool check(int x, int y) {
	int rx = root(x);
	int ry = root(y);
	return rx == ry;
}

bool cmp(Sedge x, Sedge y) { return x.w < y.w; }

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	cin >> n >> m;
	init(n);
	for (int i = 1; i <= m; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		edge.push_back({u, v, w});
	}
	sort(edge.begin(), edge.end(), cmp);

	auto it1 = edge.begin();
	for (; it1 != edge.end(); it1++) {
		merge(it1->u, it1->v);
		if (check(1, n)) {
			break;
		}
	}

	// 检查是否联通
	cout << (check(1, n) ? it1->w : -1) << endl;
	return 0;
}

你可能感兴趣的:(Algorithm,Problems,算法)