题目链接:D
题意:给定一个点数为3e5,边数为3e5的且保证连通的边权都为1的无向图,给定k个特殊点,
(
2
<
=
k
<
=
n
)
(2<=k<=n)
(2<=k<=n),定义要计算的路径长度是从1到n的最短路,现在要求你选择两个特殊点之间加一条长度为1的边,问你在所有方案中,要计算的路径长度最大的是多少。
昨晚看这一场很晚了就没打,但十一点多看了一下该题,口胡了一个做法。
首先可以知道答案一定是小于等于原来不加边的最短路的。
因为不管怎么加边都不会使得已存在的最短路变长。
两次bfs预处理出
d
i
s
1
[
x
]
,
d
i
s
n
[
x
]
dis1[x],disn[x]
dis1[x],disn[x],分别表示从
1
,
n
1,n
1,n出发到
x
x
x的最短路长度。
所以其实可以想到一个较为暴力的做法,任取两特殊点
i
,
j
i,j
i,j,计算:
M
a
x
(
m
i
n
(
d
i
s
1
[
i
]
+
d
i
s
n
[
j
]
+
1
,
d
i
s
n
[
i
]
+
d
i
s
j
[
1
]
+
1
,
d
i
s
1
[
n
]
)
)
Max(min(dis1[i]+disn[j]+1,disn[i]+disj[1]+1,dis1[n]))
Max(min(dis1[i]+disn[j]+1,disn[i]+disj[1]+1,dis1[n])),就是最终答案。
现在考虑不那么暴力的做法,枚举特殊点
x
x
x,考虑往哪个特殊点上加边,假设加到了
j
j
j上,那么dis1[x]+disn[j]+1就可能是新的最短路,其他点都没有受到影响,那要使得这条最短路尽可能的大,那其实就是找max(disn[j])。但是这里有一点需要注意,你应该找的是在bfs过程中x延伸出去特殊点中disn最大的一项。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
vector<int> G[maxn];
int dis1[maxn],disn[maxn];
queue<int> q;
bool vis[maxn];
void bfs(int st,int dis[]){
q.push(st);
memset(vis,0,sizeof(vis));
dis[st]=0;
vis[st]=1;
while(q.size()){
int u=q.front(); q.pop();
for(auto v:G[u])
if(!vis[v]){
dis[v]=dis[u]+1;
q.push(v);
vis[v]=1;
}
}
}
int b[maxn];
vector<int> v;//存储所有从n出发到特殊点的最短路径;
vector<int> te;
int main(){
int n,m,k;
cin>>n>>m>>k;
for(int i=1,x;i<=k;++i){
scanf("%d",&x);
te.push_back(x);
}
while(m--){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
bfs(1,dis1);
bfs(n,disn);
int res=0;
for(auto x:te) v.push_back(disn[x]);
sort(v.begin(),v.end());
for(auto x:te){
vector<int>::iterator it = upper_bound(v.begin(),v.end(),disn[x]);
--it;
if(it==v.begin()) continue;
--it;//将本身x排除在外;
//cout<<dis1[x]+(*it)+1<<endl;
res=max(res,min(dis1[n],dis1[x]+(*it)+1));
}
if(res==0) res=dis1[n];
cout<<res<<endl;
return 0;
}