题意 给出n个点,m条边,还有k个特殊点;
求从1到n的最短路,但又不是单纯求最短;
我们需要在这k个特殊点中选择两个点,将这两个点相连,再去求路径最长的最短路
那么 ,我们可以先跑两边spfa求出从顶点1开始的最短路和从n开始的最短路,分别为disa disb;
然后,我们再将特殊点根据disa[x]-disb[x]<disa[y]-disb[y],来排序;
为啥这样排呢,因为 disa[x]+1+disn[y]<disa[y]+1+disn[x], 移项之后便是上面的式子;
为什么是这样的式子呢,首先我们就要确定排序的宗旨,就是让路径是从1到x,从x到y,再从y到n;
而不是从1到y,从y到x,再从x到n 这样子就绕了个圈;我们也不好判断;
所以我们将特殊点处理为不用“绕圈子"的样子,这样我们就可以O(n)的复杂度来遍历;
因此,要让答案最大,我们就在每次更新完ans之后,再更新一下特殊点的左端点(根据距点1的距离更远更优来选择)
这样子代码基本就完成;
但是有一个细节;
就是可能特殊点对最短路没有贡献,意思就是,即使连接了这两个特殊点,得出的答案依旧为inf
所以我们最后得ans=min(ans,disa[n]);
代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=2e5+10; 4 const int inf=0x3f3f3f3f; 5 int a[maxn]; 6 struct node 7 { 8 int v,nxt,w; 9 }G[maxn<<1]; int head[maxn]; int num; 10 int disa[maxn]; 11 int disb[maxn]; 12 int dis[maxn]; 13 int vis[maxn]; 14 int n,m,k; 15 void add(int u,int v) 16 { 17 G[++num].v=v;G[num].nxt=head[u];G[num].w=1;head[u]=num; 18 } 19 void init() 20 { 21 memset(head,-1,sizeof(head)); 22 num=-1; 23 } 24 void spfa(int u) 25 { 26 queue<int>q; 27 memset(dis,inf,sizeof(dis)); 28 memset(vis,0,sizeof(vis)); 29 q.push(u); 30 vis[u]=1; 31 dis[u]=0; 32 while(!q.empty()){ 33 int u=q.front(); 34 q.pop(); 35 vis[u]=0; 36 for(int i=head[u];i!=-1;i=G[i].nxt){ 37 int v=G[i].v;int w=G[i].w; 38 if(dis[v]>dis[u]+w){ 39 dis[v]=dis[u]+w; 40 if(!vis[v]){ 41 vis[v]=1; 42 q.push(v); 43 } 44 } 45 } 46 } 47 if(u==1){ 48 for(int i=1;i<=n;i++) 49 disa[i]=dis[i]; 50 } 51 else{ 52 for(int i=1;i<=n;i++) 53 disb[i]=dis[i]; 54 } 55 return; 56 } 57 bool cmp(int x,int y) 58 { 59 return disa[x]-disb[x]<disa[y]-disb[y]; 60 } 61 int main() 62 { 63 init(); 64 scanf("%d%d%d",&n,&m,&k); 65 for(int i=1;i<=k;i++) scanf("%d",&a[i]); 66 for(int i=1;i<=m;i++){ 67 int u,v; 68 scanf("%d%d",&u,&v); 69 add(u,v); add(v,u); 70 } 71 spfa(1);spfa(n); 72 sort(a+1,a+1+k,cmp); 73 int ans=0; 74 int mx=disa[a[1]]; 75 for(int i=2;i<=k;i++){ 76 ans=max(ans,mx+1+disb[a[i]]); 77 mx=max(mx,disa[a[i]]); 78 } 79 ans=min(ans,disa[n]); 80 printf("%d\n",ans); 81 return 0; 82 }