題目鏈接:D
題意:給定一個點數爲3e5,邊數爲3e5的且保證連通的邊權都爲1的無向圖,給定k個特殊點,,定義要計算的路徑長度是從1到n的最短路,現在要求你選擇兩個特殊點之間加一條長度爲1的邊,問你在所有方案中,要計算的路徑長度最大的是多少。
昨晚看這一場很晚了就沒打,但十一點多看了一下該題,口胡了一個做法。
首先可以知道答案一定是小於等於原來不加邊的最短路的。
因爲不管怎麼加邊都不會使得已存在的最短路變長。
兩次bfs預處理出,分別表示從出發到的最短路長度。
所以其實可以想到一個較爲暴力的做法,任取兩特殊點,計算:
,就是最終答案。
現在考慮不那麼暴力的做法,枚舉特殊點,考慮往哪個特殊點上加邊,假設加到了上,那麼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;
}