题目链接:
https://codeforces.com/contest/1307/problem/D
题意:
在图中添加一条边,连接两个不同的特殊点,使得最短路径最大
分析:
假设连接$v$和$u$,最短路径有三种情况,第一,不走添加的边的最短路径,第二,$1->v->u->n$,第三,$1->u->v->n$
定义$dis1[]$数组为$1$到所有点的最短路径,$dis2[]$数组为$n$到所有点的最短路径
假设$dis1[v]+dis2[u]>=dis1[u]+dis2[v]$,那么$dis1[v]-dis2[v]>=dis1[u]-dis1[u]$,按照差值从小到大排序
如果$u$的位置小于$v$,那么必然满足上式,之后只需要保存$dis2$的前缀最大值即可
AC代码:
#include <bits/stdc++.h> using namespace std; #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,a,b) for (int i=b;i>=a;i--) #define pb push_back #define mp make_pair #define fi first #define se second #define SZ(x) ((int)(x).size()) typedef long long ll; typedef vector<int> VI; typedef pair<int,int> PII; const int maxn=2e5+7; const int INF=1e9+10; int dis1[maxn],dis2[maxn],n,m,k,spe[maxn]; VI ve[maxn]; struct Node{ int a,b; bool operator < (const Node other)const{ return a-b>other.a-other.b; } }node[maxn]; void bfs(int x,int dis[]){ rep(i,1,n)dis[i]=-1; queue<int>que; que.push(x); dis[x]=0; while(SZ(que)){ int now=que.front(); que.pop(); for(auto i:ve[now]){ if(dis[i]==-1){ dis[i]=dis[now]+1; que.push(i); } } } } int main() { scanf("%d %d %d",&n,&m,&k); rep(i,1,k){ scanf("%d",&spe[i]); } rep(i,1,m){ int a,b; scanf("%d %d",&a,&b); ve[a].pb(b); ve[b].pb(a); } bfs(1,dis1); bfs(n,dis2); rep(i,1,k){ int w=spe[i]; node[i]={dis1[w],dis2[w]}; } sort(node+1,node+1+k); int ans=-1,maxx=node[1].b; rep(i,2,k){ ans=max(min(dis1[n],node[i].a+maxx+1),ans); maxx=max(maxx,node[i].b); } printf("%d ",ans); return 0; }