Codeforces Round #621 (Div. 1 + Div. 2) D. Cow and Fields
题目链接
大意:给你一个无向图,k个特殊点,你要在两个不同的特殊点直接连一条无向边,使得 1−>n的最短路最长。
思路:直观的想法肯定是枚举所有情况来找到最小值,显然复杂度不允许。我们思考一下:
不连边的最短路是 len,当前两个特殊点分别是 s,t,那么这种情况下的最短路就是
min(len,min(p[s]+q[t]+1,p[t]+q[s]+1)),p数组表示 1出发的最短路,q表示从n出发的最短路。
如果可以确定 p[s]+q[t]+1,p[t]+q[s]+1的大小的话,是不是就可以只扫一遍啦。
显然我们排个序即可,排序规则是 p[s]+q[t]+1<p[t]+q[s]+1。
然后遍历一下k个特殊点:那么当前遍历到的t,那么t与之前所有的点直接的最短路都是 min(p[s]+q[t]+1,len),把 p[s]的最大值记录一下即可。
细节见代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
#define fi first
#define se second
#define pb push_back
int n,m,k;
vector<int>v[N];
int a[N],inq[N];
int dis[2][N];
void spfa(int s,int c){
queue<int>q;
for(int i=1;i<=n;i++)dis[c][i]=1e9,inq[i]=0;
dis[c][s]=0;
q.push(s);
while(!q.empty()){
int x=q.front();
inq[x]=0;
q.pop();
for(auto k:v[x]){
if(dis[c][k]>dis[c][x]+1){
dis[c][k]=dis[c][x]+1;
if(!inq[k]){
inq[k]=1;
q.push(k);
}
}
}
}
}
int main() {
ios::sync_with_stdio(false);
cin>>n>>m>>k;
for(int i=1;i<=k;i++)cin>>a[i];
for(int i=1;i<=m;i++){
int s,t;
cin>>s>>t;
v[s].pb(t);
v[t].pb(s);
}
spfa(1,0);
spfa(n,1);
int ans=0;
sort(a+1,a+1+k,[](int x,int y){
return dis[0][x]-dis[1][x]<dis[0][y]-dis[1][y];
});
int pat=dis[0][a[1]];
for(int i=2;i<=k;i++){
ans=max(ans,pat+dis[1][a[i]]+1);
pat=max(pat,dis[0][a[i]]);
}
cout<<min(ans,dis[0][n])<<'\n';
return 0;
}