牛客小白月赛24——E-旅旅旅游(最短路+并查集)

题目链接:https://ac.nowcoder.com/acm/contest/5158/E
题目描述:
牛牛国有 n n n个城市, m m m条无向道路,每条道路三个属性 a i , b i , c i a_i,b_i,c_i ai,bi,ci,表示城市 a i a_i ai与城市 b i b_i bi之间有一条长为 c i c_i ci的道路,现在牛可乐在城市 1 1 1,他想去城市 n n n。同时牛可乐非常聪明,他会将所有从 1 1 1 n n n可能的最短路径全都走一遍,之后便不再走了。
现在牛妹在城市 1 1 1,他想把所有城市走一遍,可是他不想走牛可乐走过的路,牛妹不知道他能不能将所有城市全走一遍,你能告诉她吗?
输入描述:
第一行两个数字 n , m n,m n,m,表示城市的数量和道路的数量。
接下来 m m m行,每行 3 3 3个数字 a i , b i , c i a_i,b_i,c_i ai,bi,ci,表示城市 a i a_i ai与城市 b i b_i bi之间有一条长为 c i c_i ci的道路(题目保证无自环,可能有重边)
输出描述:
如果牛妹能走遍所有城市,输出 “YES” ,否则输出 “NO”。
示例1
输入:

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

输入:

YES

说明:
城市1到城市4最短路距离是3(1->3->4),牛妹不能走这些边也能走遍所有城市。
说明
备注
1 ≤ n ≤ 1 e 5 , 1 ≤ m ≤ 5 e 5 1\le n\le1e5,1\le m\le5e5 1n1e5,1m5e5
1 ≤ a i , b i ≤ n , 1 ≤ c i ≤ 1 e 9 1\le a_i,b_i\le n,1\le c_i\le1e9 1ai,bin,1ci1e9

解题思路

如何找到所有最短路径的边?
对起点 1 1 1进行Dijkstra求得到其他结点的最短路径长度保存至 d 1 [ N ] d1[N] d1[N],对终点 n n n进行Dijkstra求得到其他结点的最短路径长度 d 2 [ N ] d2[N] d2[N],对于某一边,设其两端结点为 i , j i,j i,j,边长为 w w w,如果起点 1 1 1到结点 i i i的最短路径长度和终点 n n n到结点 j j j的最短路径长度之和等于起点 1 1 1到终点 n n n的最短路径长度,或者起点 1 1 1到结点 j j j的最短路径长度和终点 n n n到结点 i i i的最短路径长度之和等于起点 1 1 1到终点 n n n的最短路径长度,即
d 1 [ i ] + w + d 2 [ j ] = = m i n _ d i s   ∣ ∣   d 1 [ j ] + w + d 2 [ i ] = = m i n _ d i s d1[i]+w+d2[j]==min\_dis\ ||\ d1[j]+w+d2[i]==min\_dis d1[i]+w+d2[j]==min_dis  d1[j]+w+d2[i]==min_dis
那么边 i _ j i\_j i_j在最短路径上。
如何高效确定判断结点可达?
利用并查集,遍历所有的边,如果这条边不是最短路径上的边,将该边两端的顶点用并查集的 U n i o n Union Union操作合并。
最后检查每一个结点是否和其中的某个结点属于同一个并查集。
AC代码:

#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <map>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 1e5+7;
const ll INF = 0x3f3f3f3f3f3f3f3f;
int n, m;
struct Node {
    
    
	int to, w;
};
vector<Node> g[N];
ll d[2][N];
int e[3][500007];
bool vis[N]; 
void dijkstra(int s, int k) {
    
    
	memset(vis, false, sizeof(vis));
	d[k][s] = 0;
	priority_queue< pair<ll, int> > q;
	q.push(make_pair(0, s));
	while (!q.empty()) {
    
    
		int from = q.top().second;q.pop();
		if (vis[from] == true) continue;
		vis[from] = true;
		for (int i = 0; i < g[from].size(); i++) {
    
    
			int to = g[from][i].to;
			ll w = g[from][i].w;
			if (d[k][to] > d[k][from] + w) {
    
    
				d[k][to] = d[k][from] + w;
				if (vis[to]  == false) {
    
    
					q.push(make_pair(-d[k][to], to));
				}
			}
		}
	}
}
int f[N];
int find(int x) {
    
    
	return x == f[x] ? x : f[x] = find(f[x]);
}
int main() {
    
    
	scanf("%d%d", &n, &m);
	int a, b, c;
	for (int i = 1; i <= m; i++) {
    
    
		scanf("%d%d%d", &a, &b, &c);
		g[a].push_back(Node{
    
    b, c});
		g[b].push_back(Node{
    
    a, c});
		e[0][i] = a;e[1][i] = b;e[2][i] = c;
	}
	memset(d, 0x3f, sizeof(d));
	dijkstra(1, 0);
	dijkstra(n, 1);
	for (int i = 1; i <= n; i++) {
    
    
		f[i] = i;
	}
	ll dis = d[1][1];
	for (int i = 1; i <= m; i++) {
    
    
		int x = e[0][i], y = e[1][i];
		ll w = e[2][i];
		if (d[0][x] + d[1][y] + w == dis || d[1][x] + d[0][y] + w == dis) {
    
    
			continue;
		}
		int fx = find(x), fy = find(y);
		f[fx] = fy;
	}
	bool res = true;
	for (int i = 1; i <= n; i++) {
    
    
		if (find(i) != find(1)) {
    
    
			res = false;
			break;
		}
	}
	if (res) printf("YES\n");
	else printf("NO\n");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41685509/article/details/107618993