题目链接: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
1≤n≤1e5,1≤m≤5e5
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
1≤ai,bi≤n,1≤ci≤1e9
解题思路
如何找到所有最短路径的边?
对起点
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;
}