添加链接描述
题意
将所有最短路的路径都走一遍,之后就不再走了,问能否还有其他路径从
1
1
1走到
n
n
n
思路
先从
1
1
1到
n
n
n跑一次单源最短路,d1数组保存距离,再从n到1跑一次最短路,d2数组保存距离,然后用
d
1
[
x
]
+
z
+
d
2
[
y
]
=
=
d
i
s
t
a
n
c
e
∣
∣
d
1
[
y
]
+
z
+
d
2
[
x
]
=
=
d
i
s
t
a
n
c
e
d1[x] + z + d2[y] == distance || d1[y] + z + d2[x] == distance
d1[x]+z+d2[y]==distance∣∣d1[y]+z+d2[x]==distance判断(起点到
x
x
x的距离加上
x
x
x和
y
y
y之间的距离再加上
y
y
y到终点的距离,若等于
1
1
1到
n
n
n的最短路距离,说明边
x
,
y
x,y
x,y属于最短路径的边),无向边
(
x
,
y
)
(x,y)
(x,y)是否是最短路径的边,是的话就
c
o
n
t
i
n
u
e
continue
continue,否则将
x
,
y
x,y
x,y两个点合并
m
e
r
g
e
merge
merge,最后判断并查集的大小是否为
1
1
1,是则输出
Y
E
S
YES
YES。
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1e6+5;
const ll inf = 1e18;
ll fa[N], n, m, tot, d1[N], d2[N], u[N], v[N], w[N];
ll vis[N], ver[N], net[N], head[N], edge[N];
void add(ll x, ll y, ll z)
{
ver[++tot] = y;
edge[tot] = z;
net[tot] = head[x];
head[x] = tot;
}
void init(ll n)
{
for(ll i = 1; i <= n; i++)
fa[i] = i;
}
ll find(ll x)
{
return (x == fa[x] ? x : fa[x] = find(fa[x]));
}
void merge(ll x, ll y)
{
fa[find(x)] = find(y);
}
void dijkstra(ll s, ll d[])
{
priority_queue< pair<ll, ll> > q;
fill(d, d+1+n, inf);
memset(vis, 0, sizeof vis);
d[s] = 0;
q.push({0, s});
while(q.size())
{
ll x = q.top().second;
q.pop();
if(vis[x])
continue;
for(ll i = head[x]; i; i = net[i])
{
ll y = ver[i], z = edge[i];
if(d[y] > d[x] + z)
{
d[y] = d[x] + z;
q.push({-d[y], y});
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for(ll i = 1; i <= m; i++)
{
scanf("%d%d%d", &u[i], &v[i], &w[i]);
add(u[i], v[i], w[i]);
add(v[i], u[i], w[i]);
}
dijkstra(1, d1);
dijkstra(n, d2);
ll distance = d2[1];
//cout << distance << endl;
init(n);
for(ll i = 1; i <= m; i++)
{
ll x = u[i], y = v[i], z = w[i];
if(d1[x] + z + d2[y] == distance || d1[y] + z + d2[x] == distance)
continue;
ll fx = find(x), fy = find(y);
if(fx != fy)
merge(x, y);
}
ll cnt = 0;
for(ll i = 1; i <= n; i++)
if(fa[i] == i)
cnt++;
cout << (cnt==1?"YES":"NO") <<'\n';
return 0;
}