整张无向图的边权为1。
首先求出 1 , n 1,n 1,n 两个点的单源最短路径。这 k k k 个特殊点中,我们令第 a a a 个特殊点到 1 1 1 的距离为 x a x_a xa,到 n n n 的距离为 y a y_a ya。设答案是连接 a , b a,b a,b 两点。
我们的目的就是最大化 m i n ( x a + y b + 1 , y a + x b + 1 ) min(x_{a} + y_{b} + 1,y_{a} + x_{b} +1) min(xa+yb+1,ya+xb+1)
为了不失一般性,我们设
x a + y b ≤ y a + x b 。 x_{a} +y_{b}≤y_{a}+ x_{b}。 xa+yb≤ya+xb。
我们可以化简成(分离变量,因为我们必须是同一个 a a a 才能排序)
x a − y a ≤ x b − y b x_{a}-y_{a}≤x_{b}-y_{b} xa−ya≤xb−yb
我们按照 x a − y a x_{a}-y_{a} xa−ya来排序,这样排完序之后的 a a a 和 b b b就 拥有了一个性质: a < b aa<b( a a a 一定在 b b b 的前面)
因此我们倒序处理Max[i]
数组,表示的是 i i i 右边(包括自己)最大的 y i y_i yi。
然后我们正序求当前结点 a a a 的 x a + y b + 1 x_a + y_b + 1 xa+yb+1(只能和右边 b b b 的匹配) 的最大值即可。
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
const int N = 510007, M = 510007, INF = 0x3f3f3f3f;
int t;
int n,m,k;
int dist[N];
bool vis[N];
int ver[M],nex[M],edge[M],head[N],tot;
int cnt;
int a[N],b[N];
int maxx,minn;
map<int,int>mp;
int Max[N];
int dis1[N],disn[N];
void add(int x,int y,int z){
ver[tot] = y;
nex[tot] = head[x];
edge[tot] = z;
head[x] = tot ++ ;
}
struct node{
int dis1,disn;
bool operator<(const node &t)const{
return dis1 - disn < t.dis1 - t.disn;
}
}pos[N];
priority_queue<PII,vector<PII>,greater<PII> >q;
void Dijkstra(int S){
memset(dist,0x3f,sizeof dist);
memset(vis,0,sizeof vis);
dist[S] = 0;
q.push({dist[S],S});
while(q.size()){
int x = q.top().second;
q.pop();
if(vis[x])continue;
vis[x] = true;
for(int i = head[x];~i;i = nex[i]){
int y = ver[i],z = edge[i];
if(dist[y] > dist[x] + z){
dist[y] = dist[x] + z;
q.push({dist[y],y});
}
}
}
}
int main(){
memset(head,-1,sizeof head);
scanf("%d%d%d",&n,&m,&k);
for(int i = 1;i <= k;++i)
scanf("%d",&a[i]);
for(int i = 1;i <= m;++i){
int x,y;
scanf("%d%d",&x,&y);
add(x,y,1);
add(y,x,1);
}
Dijkstra(1);
for(int i = 1;i <= n;++i)
dis1[i] = dist[i];
Dijkstra(n);
for(int i = 1;i <= n;++i)
disn[i] = dist[i];
for(int i = 1;i <= k;++i)
pos[i] = {dis1[a[i]],disn[a[i]]};
sort(pos + 1,pos + 1 + k);
int ans = 0;
for(int i = k;i;--i)
Max[i] = max(Max[i + 1],pos[i].disn);
for(int i = 1;i < k;++i)
ans = max(ans,pos[i].dis1 + Max[i + 1] + 1);
ans = min(ans,dis1[n]);
printf("%d\n",ans);
return 0;
}