【ETOJ P1074】能不能走到捏 题解(无向图+FloodFill算法+深度优先搜索+二分答案)

27 阅读3分钟

题目描述

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

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

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

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

输入格式

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

接下来 mm 行,每行三个整数 ui,vi,wiu_i,v_i,w_i 表示在 uiu_iviv_i 之间存在一条权值为 wiw_i 的无向边。 (1ui,vin,0wi104)(1 \leq u_i, v_i \leq n, 0 \leq w_i \leq 10^4)

输出格式

一个整数表示答案。

样例输入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

思路

首先,定义一个结构体Sedge,用来存储边的终点和权重。然后定义一个全局的边数组edge,用来存储图的信息。

在主函数中,先从输入中读取节点数量和边的数量,然后读取每条边的信息,包括起点、终点和权重,并将这些信息存储在edge数组中。

接下来使用二分查找的方法来寻找满足条件的权重上限。定义了一个check函数,这个函数接受一个参数,代表权重的上限。然后使用DFS的方法来遍历图,如果存在一条从起点到终点的路径,路径上所有边的权重都不超过这个上限,那么就返回true,否则返回false。在DFS的过程中,使用了一个栈来存储待遍历的节点,使用一个bitset来记录已经遍历过的节点。

在主函数中,使用二分查找的方法来寻找满足条件的权重上限。初始时,上限设置为10000,下限设置为0。然后在下限和上限之间进行二分查找,每次取中点作为权重上限,然后调用check函数来检查是否存在满足条件的路径。如果存在,那么说明这个权重上限可能偏大,需要将上限设置为中点;如果不存在,那么说明这个权重上限偏小,需要将下限设置为中点。如此反复,直到找到满足条件的最小的权重上限。

最后,再次调用check函数来检查是否存在一条从起点到终点的路径,如果存在,那么输出这个权重上限,否则输出-1。


AC代码

#include <algorithm>
#include <bitset>
#include <iostream>
#include <stack>
#include <vector>
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;

const int N = 1e6 + 7;

struct Sedge {
	int to;
	int w;
};

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

bool check(int x) {
	stack<int> stk;
	bitset<N> vis;
	vis.reset();
	stk.push(1);
	while (stk.size()) {
		int t = stk.top();
		stk.pop();
		vis[t] = 1;
		for (const auto i : edge[t]) {
			if (vis[i.to] || i.w > x) {
				continue;
			}
			stk.push(i.to);
		}
	}
	return vis[n];
}

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

	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int u, v, w;
		cin >> u >> v >> w;
		edge[u].push_back({v, w});
		edge[v].push_back({u, w});
	}

	int l = 0;
	int r = 1e4;
	while (l + 1 < r) {
		int mid = (l + r) >> 1;
		if (check(mid)) {
			// 能到达,mid偏大
			r = mid;
		} else {
			// 不能到达,mid偏小
			l = mid;
		}
	}

	// 检查是否联通
	cout << (check(r) ? r : -1) << endl;
	return 0;
}