CF-189 E. Weak Memory---二分+动态更新最短路

Zart PMP is qualified for ICPC World Finals in Harbin, China. After team excursion to Sun Island Park for snow sculpture art exposition, PMP should get back to buses before they leave. But the park is really big and he does not know how to find them.

The park has n intersections numbered 1 through n. There are m bidirectional roads that connect some pairs of these intersections. At k intersections, ICPC volunteers are helping the teams and showing them the way to their destinations. Locations of volunteers are fixed and distinct.

When PMP asks a volunteer the way to bus station, he/she can tell him the whole path. But the park is fully covered with ice and snow and everywhere looks almost the same. So PMP can only memorize at most q intersections after each question (excluding the intersection they are currently standing). He always tells volunteers about his weak memory and if there is no direct path of length (in number of roads) at most q that leads to bus station, the volunteer will guide PMP to another volunteer (who is at most q intersections away, of course). ICPC volunteers know the area very well and always tell PMP the best way. So if there exists a way to bus stations, PMP will definitely find it.

PMP’s initial location is intersection s and the buses are at intersection t. There will always be a volunteer at intersection s. Your job is to find out the minimum q which guarantees that PMP can find the buses.

Input
The first line contains three space-separated integers n, m, k (2 ≤ n ≤ 105, 0 ≤ m ≤ 2·105, 1 ≤ k ≤ n) — the number of intersections, roads and volunteers, respectively. Next line contains k distinct space-separated integers between 1 and n inclusive — the numbers of cities where volunteers are located.

Next m lines describe the roads. The i-th of these lines contains two space-separated integers ui, vi (1 ≤ ui, vi ≤ n, ui ≠ vi) — two intersections that i-th road connects. There will be at most one road between any two intersections.

Last line of input contains two space-separated integers s, t (1 ≤ s, t ≤ n, s ≠ t) — the initial location of PMP and the location of the buses. It might not always be possible to reach t from s.

It is guaranteed that there is always a volunteer at intersection s.

Output
Print on the only line the answer to the problem — the minimum value of q which guarantees that PMP can find the buses. If PMP cannot reach the buses at all, output -1 instead.

cf题目
题目大意:n个点构成的图,其中一些点算作补给点,玩家有q的精力上限(每走一条路消耗1精力),到达补给点会补满,求从原点到达目标点所需要的最小q

题解:有q即二分,spfa+单调队列优化求最短路,同时动态更新路径长度,每到达一个补给点即更新此补给点为原点(距离0),判断能否到达终点,算法复杂度大概nmlogq,勉强可以过

#include<algorithm>
#include<iostream>
#include<queue>
#include<memory.h>
#define me(x,y) memset(x,y,sizeof(x))
#define P pair<int,int> 
using namespace std;
const int N = 2e5 + 10, inf = 0x7f7f7f7f;
int n, m, k, head[N], s, t, v[N], cnt, vis[N], d[N];

struct edge {
	int to=0, nxt=0;
}e[N * 2];

inline void add_(int f, int t) {
	e[++cnt].to = t; e[cnt].nxt = head[f]; head[f] = cnt;
}
bool SPFA(int mid){//重点,距离更新版SPFA
    for (int i = 1; i <= n; i++) d[i] = inf;
    d[s] = 0;
    priority_queue<P > q;
    q.push(make_pair(0, s));
    while (!q.empty()){
        int u = q.top().second;
        int resp = -q.top().first;//为什么入队的时候是用负数
        //是因为优先队列默认最高处为最大,设置为负数,则第一个弹出距离最小的路,来进行优化
        q.pop();
        if (u == t) return true;
        if (resp == mid) continue;//到达最大距离且不是终点,因为若到达志愿者自动更新距离0
        if (resp > d[u]) continue;//重复更新,且距离变大则跳过
        for (int i = head[u]; i; i=e[i].nxt){
            int a = e[i].to;
            if (d[a] <= resp + 1) continue;//最短路跳过
            if (v[a]){
                d[a] = 0;//遇到志愿者,则更新距离0,同时入队
                q.push(make_pair(0, a));
            }
            else{
                d[a] = resp + 1;
                q.push(make_pair(-d[a], a));
            }
        }
    }
    return false;
}
int main() {
	cin >> n >> m >> k;
	for (int i = 0; i < k; i++) {
		int V;
		cin >> V;
		v[V]++;
	}
	for (int i = 0; i < m; i++) {
		int f, t;
		cin >> f >> t;
		add_(f, t); add_(t, f);
	}
	cin >> s >> t;
    int max_ = n + 1, min_ = 1;
    if (!SPFA(max_)) {
        cout << -1 << endl;
        return 0;
    }
    int mid;
    while (max_ > min_) {
        mid = (max_ + min_) / 2;
        if (SPFA(mid))max_ = mid;
        else min_ = mid+1;
    }
    if (SPFA(min_))max_ = min_;
    cout << max_ << endl;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值