差点忘记补题.
这题是一个非常好的结论题:
首先可以确定,加一条边之后,最短路会变小或者不变。
看了网上非常多的对于这个题目的看法,现在终于搞懂原理。
很容易误解的一个点:为什么按照差值排序?差值排序的目的?
很多以为差值排序是为了选择哪几个点排序——错误认识
差值排序只是为了得到 顺序:
加一条边必定会引起一条最短路改变或者不改变。预先处理出 a,b两个数组,a_x代表1~x的最短距离,b_x代表n~x的最短距离,那么如果选择两个点(x,y)的话,新的最短路的权值为:a_x+b_y+1 或者 a_y+b_x+1,我们知道这两个里面只有一条是最短路(其实就是 谁在前面 ,否则的话会多走重复的路)。所以假设 前者为最短路 a_x+b_y+1<a_y+b_x+1 ——— a_x-a_y<b_x-b_y, 那么这个式子也就证明 当x的差值比y的差值小的话,x一定是链接1的那个点(x在y的前面),这样一来我们只需要得到一个后缀y的最大值就可以了。最后与最短路取个min
/*** keep hungry and calm CoolGuang!***/
#include <bits/stdc++.h>
#include<stdio.h>
#include<vector>
#include<algorithm>
#pragma GCC optimize(2)
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pp;
const ll INF=1e18;
const ll maxn=1e6+5;
const int mod=1e9+7;
inline bool read(ll &num)
{char in;bool IsN=false;in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
vector<int>v[maxn];
ll num[maxn];
ll a[maxn],b[maxn];
int vis[maxn];
struct node{
ll a,b;
bool friend operator<(node a,node b){
return a.a-a.b<b.a-b.b;
}
}save[maxn];
void bfs(int s,ll *p){
for(int i=1;i<=n;i++) vis[i]=0;
queue<int>q;
q.push(s);vis[s]=1;
while(!q.empty()){
int u=q.front();q.pop();
int sz=v[u].size();
for(int k=0;k<sz;k++){
int e=v[u][k];
if(!vis[e]){
p[e]=p[u]+1;
vis[e]=1;
q.push(e);
}
}
}
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&p);
for(int i=1;i<=p;i++) scanf("%lld",&num[i]);
for(int i=1;i<=m;i++){
int x,y;scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
bfs(1,a);bfs(n,b);
for(int i=1;i<=p;i++){
save[i].a=a[num[i]];
save[i].b=b[num[i]];
}
sort(save+1,save+1+p);
ll maxl=save[p].b;
ll ans=-INF;
for(int i=p-1;i>=1;i--){
ans=max(ans,save[i].a+maxl+1);
maxl=max(maxl,save[i].b);
}
printf("%lld\n",min(ans,a[n]));
return 0;
}