题目链接:https://www.luogu.com.cn/problem/CF187C
解题思路:
首先要求最小的 (q) ,考虑二分 (q)。
在 (q) 确定的情况下,使用 BFS 可以得到从 (s) 到 (t) 是否连通,但是因为这里我其实希望到达每个节点的时候能量值尽可能地大,所以使用优先队列,优先遍历到达该点的时候能量值最大的状态。
示例代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010, maxm = 200020;
struct Edge {
int v, nxt;
Edge() {};
Edge(int _v, int _nxt) { v = _v; nxt = _nxt; }
} edge[maxm<<1];
int n, m, k, s, t, head[maxn], ecnt;
bool isvolunteer[maxn];
void init() {
ecnt = 0;
memset(head, -1, sizeof(int)*(n+1));
}
void addedge(int u, int v) {
edge[ecnt] = Edge(v, head[u]); head[u] = ecnt ++;
edge[ecnt] = Edge(u, head[v]); head[v] = ecnt ++;
}
struct Node {
int u, val;
Node() {};
Node(int _u, int _val) { u = _u; val = _val; }
bool operator < (Node b) const {
return val < b.val;
}
};
priority_queue<Node> que;
int dis[maxn];
bool check(int q) {
while (!que.empty()) que.pop();
memset(dis, -1, sizeof(int)*(n+1));
dis[s] = q;
que.push(Node(s, q));
while (!que.empty()) {
Node nd = que.top();
que.pop();
int u = nd.u, val = nd.val;
if (val == 0) continue;
for (int i = head[u]; i != -1; i = edge[i].nxt) {
int v = edge[i].v, val2 = val - 1;
if (isvolunteer[v]) val2 = q;
if (v == t) return true;
if (dis[v] < val2) {
dis[v] = val2;
que.push(Node(v, val2));
}
}
}
return false;
}
void solve() {
int L = 1, R = n, res = -1;
while (L <= R) {
int mid = (L + R) / 2;
if (check(mid)) {
res = mid;
R = mid - 1;
}
else L = mid + 1;
}
printf("%d
", res);
}
int main() {
scanf("%d%d%d", &n, &m, &k);
for (int i = 0; i < k; i ++) {
int a;
scanf("%d", &a);
isvolunteer[a] = true;
}
init();
while (m --) {
int a, b;
scanf("%d%d", &a, &b);
addedge(a, b);
}
scanf("%d%d", &s, &t);
solve();
return 0;
}