codeforces-#621-D

codeforces-#621-D

七月 08, 2020

D. Cow and Fields

题意
有n个点 m条边 k个特殊点
现在给出k个特殊点下标
和已有的m条边
问在k个特殊点中选两个点建一条边
使得1到n的最短路最大

题解
对于两个特殊点 x y
如果在这两点之间建立一条边那么经过这两点的最短路长为
min(1->x+y->n , 1->y+x->n)中产生
假设(1->x+y->n) < (1->y+x->n) 为了使最短路更长
我们选择更大的 (1->x+y->n) 同时又要满足(1->x+y->n) < (1->y+x->n)
所以将(1->x+y->n) < (1->y+x->n)转化为(1->x - x->n) <(1->y- y->n)
此时选择两个特殊点 x y 时只要满足 (1->x - x->n) <(1->y- y->n)
那么 (1->x+y->n) 将有可能成为最长的最短路
所以根据(1->x - x->n) <(1->y- y->n) 将特殊点排序
现在要想 (1->x+y->n) 尽量大 在满足(1->x - x->n) <(1->y- y->n) 的前提条件下 更新排序后前i个特殊点1-> i的最大值 maxp + i->y的距离+1 就是加边后最长最短路
注意最长的最短路不会比原有1->n的路径长

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# include<bits/stdc++.h>

using namespace std;
typedef long long ll;

# define endl '\n'

const int maxn=(int)2e5+10;
int special[(int)2e5+4];
vector<int>point[(int)2e5+5];
int dis[3][(int)2e5+4];
void bfs(int pos,int type){
dis[type][pos]=0;
queue<int>q;q.push(pos);
while(!q.empty()){
int now=q.front();q.pop();
for(auto i:point[now]){
if(dis[type][i]==maxn){
dis[type][i]=dis[type][now]+1;
q.push(i);
}
}
}
}
int main(){
int n,m,k;cin>>n>>m>>k;
for(int i=0;i<=n;i++)dis[1][i]=maxn,dis[0][i]=maxn;
for(int i=0;i<k;i++)cin>>special[i];
for(int i=0;i<m;i++){
int x,y;cin>>x>>y;
point[x].push_back(y);
point[y].push_back(x);
}
bfs(1,0);bfs(n,1);
vector<pair<int,int> >sp;
for(int i=0;i<k;i++){
sp.push_back({dis[0][special[i]]-dis[1][special[i]],special[i]});
}
sort(sp.begin(),sp.end());
int ans=0,maxp=-maxn;
for(auto i:sp){
int pos=i.second;
ans=max(ans,maxp+dis[1][pos]);
maxp=max(maxp,dis[0][pos]);
///此处更新可能会出现在一个特殊点上建环即ans=dis[0][pos] +dis[1][pos] 最后默认作为两点间建边多+1导致超过原先最短路
}
cout<<min(ans+1,dis[0][n])<<endl;
}