题目大意:
n
n
n个点
m
m
m条遍的无向图,如果点
i
i
i在点
u
u
u到点
v
v
v的最短路径(
u
u
u到
v
v
v的边数最少)上,那么记这些点为集合
I
(
u
,
v
)
I(u,v)
I(u,v)
有
k
k
k个询问,问集合
I
(
u
,
v
)
I(u,v)
I(u,v)
解题思路:
每次询问以u为起点跑一遍
D
i
j
Dij
Dij,将以
u
u
u为起点到其他点的最短路记为
d
i
s
1
dis1
dis1,再以
v
v
v为起点跑一遍
D
i
j
Dij
Dij,记为
d
i
s
2
dis2
dis2
∀
i
ϵ
[
1
,
n
]
\forall i\epsilon [1,n]
∀iϵ[1,n],若
d
i
s
1
[
i
]
+
d
i
s
2
[
i
]
=
d
i
s
1
[
v
]
(
d
i
s
2
[
u
]
)
dis1[i]+dis2[i]=dis1[v](dis2[u])
dis1[i]+dis2[i]=dis1[v](dis2[u])那么
i
ϵ
I
(
u
,
v
)
i\epsilon I(u,v)
iϵI(u,v)
A c c e p t e d c o d e Accepted\ code Accepted code
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
const int inf = 1e9;
struct Line {
int to, w, next;
}e[5005];
priority_queue < pair<int, int> > q;
int n, m, u, v, cnt;
int dis[50][2], vis[50], last[50], a[5005];
inline void addline(int x, int y) {
e[++cnt] = (Line){y, 1, last[x]}; last[x] = cnt;
}
void dij(int S, int nm) {
for (int i = 1; i <= n; ++i) dis[i][nm] = inf, vis[i] = 0;
dis[S][nm] = 0;
while (q.size()) q.pop();
q.push(make_pair(0, S));
while (q.size()) {
int x = q.top().second; q.pop();
if (vis[x]) continue;
vis[x] = 1;
for (int i = last[x]; i; i = e[i].next) {
int y = e[i].to;
if (dis[y][nm] > dis[x][nm] + e[i].w) {
dis[y][nm] = dis[x][nm] + e[i].w;
if (!vis[y]) q.push(make_pair(-dis[y][nm], y));
}
}
}
return;
}
int main() {
scanf("%d %d", &n, &m);
for (int i = 1, x = 0, y = 0; i <= m; ++i)
scanf("%d %d", &x, &y), addline(x, y), addline(y, x);
int Q = 0; scanf("%d", &Q);
while (Q--) {
scanf("%d %d", &u, &v);
dij(u, 0); dij(v, 1);
for (int i = 1; i <= n; ++i)
if (dis[i][0] + dis[i][1] == dis[v][0]) printf("%d ", i);
printf("\n");
}
}