题目
有 个村庄,编号 到 。
村庄之间有 条无向道路,第 条道路连接村庄 和村庄 ,长度是 。
所有村庄都是连通的。
共有 个村庄有商店,第 个有商店的村庄编号是 。
然后给出 个询问,第 个询问给出一个村庄的编号 ,问该村庄距离最近的商店有多远?
输入格式
第一行包含两个整数 。
接下来 行,每行包含三个整数 ,表示第 条道路连接村庄 和村庄 ,长度是 。
再一行包含整数 。
接下来 行,每行包含一个整数 ,表示第 个有商店的村庄编号是 。
再一行包含整数 。
接下来 行,每行包含一个整数 ,表示询问编号为 的村庄与其距离最近的商店之间的距离。
输出格式
对于每个询问,输出该询问的结果。
数据范围
,
,
,
,
输入样例:
7 7
1 2 5
1 4 3
2 3 2
2 5 1
3 6 7
5 6 8
6 7 6
3
7
5
4
7
1
2
3
4
5
6
7
输出样例:
3
1
3
0
0
6
0
解题
方法一:Dijkstra 算法
思路
对于某一村庄顶点 ,设其可以到达的 个有商店的村庄顶点(以下简称为商店顶点)分别为 ,那么 到商店节点的路径集合为 ,那么 到与其最近商店之间距离为 ,到这里直接做的话,对于每个村庄节点都要求 次最短路再取最小,显然会超时,所以需要转换。
构造一个虚拟源点 ,把所有商店顶点和该虚拟源点之间连一条权值为 的通路,那么 到 的路径集合为 (由于 只与商店顶点有通路,所以从 到任意一个村庄节点都必至少经过一个商店顶点)。
此时: ,同理: ,所以 ,那么 。
此时问题就变成了一个最朴素的单源最短路问题,只要求一遍 到所有村庄节点的最短路然后对每个村庄节点在 dists
数组里取最短距离即可。
本题没有负权边,且是一个稠密图,所以使用堆优化版Dijkstra算法求解。
代码
import java.util.*;
import java.io.*;
public class Main {
static final int INF = 0x3f3f3f3f;
static int n, m;
static int[] h, e, ne, w;
static int idx;
static int k;
static int[] dists;
static boolean[] vis;
static Queue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
static void dijkstra() {
Arrays.fill(dists, INF);
dists[0] = 0;
pq.offer(new int[]{0, 0});
while (!pq.isEmpty()) {
int[] curr = pq.poll();
int d = curr[0], mn = curr[1];
if (vis[mn]) continue;
for (int i = h[mn]; i != -1; i = ne[i]) {
int v = e[i];
if (d + w[i] < dists[v]) {
dists[v] = d + w[i];
pq.offer(new int[]{dists[v], v});
}
}
}
}
static void add(int a, int b, int c) {
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
in.nextToken();
n = (int) in.nval;
in.nextToken();
m = (int) in.nval;
h = new int[n + 1];
e = new int[m * 2 + 2 * n];
ne = new int[m * 2 + 2 * n];
w = new int[m * 2 + 2 * n];
dists = new int[n + 1];
vis = new boolean[n + 1];
Arrays.fill(h, -1);
while (m-- > 0) {
in.nextToken();
int x = (int) in.nval;
in.nextToken();
int y = (int) in.nval;
in.nextToken();
int z = (int) in.nval;
add(x, y, z);
add(y, x, z);
}
in.nextToken();
k = (int) in.nval;
for (int i = 0; i < k; ++i) {
in.nextToken();
int x = (int) in.nval;
add(x, 0, 0);
add(0, x, 0);
}
dijkstra();
in.nextToken();
int q = (int) in.nval;
while (q-- > 0) {
in.nextToken();
int y = (int) in.nval;
System.out.println(dists[y]);
}
}
}
评论区