Gym 103117 Problem - Spicy Restaurant
题目类型:搜索、BFS、打表
题意:
有 n 个火锅店位置为 1~n,每个火锅店都有一个辣度,并且 n 个火锅店之
间有 m 条无向边相连。现在有 q 组询问,每次给出一位游客的具体位置,和他能
忍受的最大辣度。求出这个游客可以到达的辣度不超过其忍耐限度且途经路径最少
的火锅店,并输出最短的路径长度,如果不存在这样的饭店则输出 -1。
分析:
看到求最短路径很容易想到用 BFS,但是查询有 5e5次,显然不能每次都搜
一遍。考虑到 BFS 从终点到起点的最短距离与起点到终点的最短距离都是一样的,
所以反过来考虑,将辣度为 a 的所有点添加到队列中,然后进行BFS搜索,当所
有点搜索完后可以得到所有点到辣度为 a 的点的最短距离,而辣度的取值只有100
种,所以进行100次BFS则可以得到一个所有点到辣度为 ai 的最短距离的表。在询
问时枚举以 p 为终点辣度 <= x 的最短距离即可。
代码:
static Node[] R;
static int[] w;
static V[] v;
static int[][] map;
static boolean[] vis;
static int[] head;
static int[] edge;
static int[] next;
static int idx;
public static void solve() throws IOException {
int n = nextInt();
int m = nextInt();
int q = nextInt();
map = new int[101][n + 1];
for (int i = 0; i < 101; i++) {
for (int j = 0; j < n + 1; j++) {
map[i][j] = INF;
}
}
idx = 0;
head = new int[200010];
next = new int[200010];
edge = new int[200010];
Arrays.fill(head, -1);
R = new Node[n + 1];
w = new int[n + 1];
vis = new boolean[n + 1];
V c = new V();
for (int i = 1; i <= n; i++) {
R[i] = new Node(i, nextInt());
w[i] = R[i].w;
c.add(w[i]);
}
c.unique();
Arrays.sort(R, 1, n + 1, new Comparator<Node>() {
@Override
public int compare(Main.Node o1, Main.Node o2) {
if (o1.w != o2.w) return o1.w - o2.w;
return o1.pos - o2.pos;
}
});
int Min = R[1].w;
for (int i = 0; i < m; i++) {
int a = nextInt();
int b = nextInt();
addEdge(a, b);
addEdge(b, a);
}
for (int i = 0; i < c.size; i++) {
bfs(c.get(i));
}
while (q-- > 0) {
int p = nextInt();
int x = nextInt();
if (x < Min) {
pw.println(-1);
continue ;
}
if (w[p] <= x) {
pw.println(0);
continue ;
}
int ans = INF;
for (int i = 1; i <= x; i++) {
if (map[i][p] != INF) {
ans = Math.min(ans, map[i][p]);
}
}
if (ans == INF) ans = -1;
pw.println(ans);
}
}
public static void bfs(int x) {
Deque<Point> q = new ArrayDeque<>();
Arrays.fill(vis, false);
int l = lowerBound(x);
int r = upperBound(x);
for (int i = l; i <= r; i++) {
q.add(new Point(R[i].pos, 0));
vis[R[i].pos] = true;
map[x][R[i].pos] = 0;
}
while (!q.isEmpty()) {
Point e = q.poll();
for (int i = head[e.pos]; i != -1; i = next[i]) {
int inx = edge[i];
if (!vis[inx]) {
vis[inx] = true;
q.add(new Point(inx, e.step + 1));
map[x][inx] = Math.min(map[x][inx], e.step + 1);
}
}
}
}
public static int lowerBound(int aim) {
int l = 1, r = w.length - 1;
while (l < r) {
int mid = l + r >> 1;
if (R[mid].w >= aim) r = mid;
else l = mid + 1;
}
return r;
}
public static int upperBound(int aim) {
int l = 1, r = w.length - 1;
while (l < r) {
int mid = l + r + 1 >> 1;
if (R[mid].w <= aim) l = mid;
else r = mid - 1;
}
return l;
}
public static void addEdge(int a, int b) {
edge[idx] = b;
next[idx] = head[a];
head[a] = idx;
idx++;
}
/******************************************************************************************/
static class V {
int[] v;
int maxSize;
int size;
public V() {
maxSize = 8;
v = new int[maxSize];
size = 0;
}
public void add(int x) {
v[size++] = x;
check();
}
public int get(int inx) { return v[inx]; }
public void sort() { Arrays.sort(v, 0, size); }
public void check() {
if (size > (maxSize >> 2) * 3) {
maxSize <<= 1;
int[] t = new int[maxSize];
System.arraycopy(v, 0, t, 0, size);
v = t;
}
}
public void unique() {
if (size == 0) return ;
sort();
int q = 1, p = 1;
while (p < size) {
if (v[q - 1] != v[p]) v[q++] = v[p];
p++;
}
size = q;
}
}
static class Point {
int pos;
int step;
public Point(int pos, int step) {
this.pos = pos;
this.step = step;
}
}
static class Node {
int pos;
int w;
public Node(int pos, int w) {
this.pos = pos;
this.w = w;
}
}
/******************************************************************************************/
// Fast I/O