题意:
一幅图,n个点,m条边。有k个特殊点,我们要任意选两个特殊点建边,起点为1,终点为n,求从起点到终点的最短路的最大值。
题解:
原图有一个最短路d,这是答案的上限,即 ans<=d.
最开始的想法就是0(n^2)暴力枚举,dis1[i]为起点到各点的最短路,dis2[i]为终点到各点的最短路,但很明显会超时,所以考虑当我们选择了两个点 i , j 建边并且强制走这条边时,最短路要么为dis1[i]+dis2[j]+1,要么为dis1[j]+dis2[i]+1,假如为1->i->j->n,那么满足dis1[i]+dis2[j]<dis1[j]+dis2[i],移项得dis1[i]-dis2[i]<dis1[j]-dis2[j],也就是说当dis1[i]-dis2[i]小的时候,那么会先到这个点,我们就可以根据这个排序k个点,既然要算dis1[i]+dis2[j]+1的最大值,我们就遍历一遍排序后的k个点,然后维护前缀dis1[i]最大值,当我们遍历到点 j 时,前【1,j-1】个点的dis1的最大值已经求出来了,那么直接与dis2[j]相加与ans比较更新最大值,最后还要和原图的最短路d比较取最小。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss std::ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
const int MAXN=2e5+5;
int dis1[MAXN];
int dis2[MAXN];
int vis[MAXN];
struct A
{
int a;
int val;
}f[MAXN];
bool cmp(A x,A y)
{
return x.val<y.val;
}
struct Node
{
int to;
int next;
int cost;
}e[MAXN<<1];
struct node
{
int pos;
ll val;
friend bool operator<(node a,node b)
{
return a.val>b.val;
}
};
int head[MAXN];
int cnt=0;
void add(int u,int v)
{
e[cnt].to=v;
e[cnt].next=head[u];
e[cnt].cost=1;
head[u]=cnt++;
}
void solve1(int s)
{
memset(vis,0,sizeof vis);
memset(dis1,0x3f3f3f,sizeof dis1);
priority_queue<node> q;
q.push(node{
s,0});
dis1[s]=0;
while(!q.empty())
{
node now=q.top();
q.pop();
if(vis[now.pos]) continue;
vis[now.pos]=1;
for(int i=head[now.pos];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(dis1[v]>now.val+e[i].cost)
{
dis1[v]=now.val+e[i].cost;
q.push(node{
v,dis1[v]});
}
}
}
}
void solve2(int s)
{
memset(vis,0,sizeof vis);
memset(dis2,0x3f3f3f,sizeof dis2);
priority_queue<node> q;
q.push(node{
s,0});
dis2[s]=0;
while(!q.empty())
{
node now=q.top();
q.pop();
if(vis[now.pos]) continue;
vis[now.pos]=1;
for(int i=head[now.pos];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(dis2[v]>now.val+e[i].cost)
{
dis2[v]=now.val+e[i].cost;
q.push(node{
v,dis2[v]});
}
}
}
}
int main()
{
memset(head,-1,sizeof head);
int n,m;
int k;
cin>>n>>m>>k;
for(int i=1;i<=k;i++)
{
cin>>f[i].a;
}
int u,v;
for(int i=1;i<=m;i++)
{
cin>>u>>v;
add(u,v);
add(v,u);
}
solve1(1);
solve2(n);
for(int i=1;i<=k;i++)
{
f[i].val=dis1[f[i].a]-dis2[f[i].a];
}
sort(f+1,f+1+k,cmp);
int maxx=dis1[f[1].a];
int ans=0;
for(int i=2;i<=k;i++)
{
ans=max(ans,maxx+dis2[f[i].a]+1);
maxx=max(maxx,dis1[f[i].a]);
}
ans=min(ans,dis1[n]);
cout<<ans<<endl;
}