codeforces 621 D Cow and Fields

题目链接: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 1n出发到 x x x的最短路长度。
所以其实可以想到一个较为暴力的做法,任取两特殊点 i , j i,j ij,计算:
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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值