CodeForces 1307D. Cow and Fields【BFS】

传送门

题意

给一个边权为 \(1\) 的无向连通图,和 \(k\) 个特殊点,
你必须在这 \(k\) 个点中选择两个点建一条边,
求建边后从点 \(1\) 到点 \(n\) 的最短路最长可以是多少。

题解

真没想到这题最终是要枚举的。
首先可以两次 bfs 算出每个点到起点和终点的最短距离 \(ds[x],dt[x]\)
如果要在点 \(x,y\) 中建一条边的话,就可以形成两条路径:\(ds[x]+1+dt[y],ds[y]+1+dt[x]\)
那么可能是最短路的那条一定是 \(min(ds[x]+1+dt[y],ds[y]+1+dt[x])\)
如果这条路的走法是 \(x\)->\(y\) 的话,一定满足 \(ds[x]+1+dt[y]<ds[y]+1+dt[x]\)\(ds[x]-dt[x]<ds[y]-dt[y]\)
那么我把所有特殊点按照 \(ds[x]-dt[x]\) 从小到大排序,这样从 起点 到 任意一个排在我前面的点 建一条边到 我 到 终点,形成一条路径,我们要使这个路径尽可能大,
于是我可以遍历特殊点,取它前面得点中最大的 \(ds\) 值,然后加上 \(1+dt[x]\),取最大值。
而这样遍历一下找出来的最大值是我假设一定走了我加上的边后的最短路径,人家本来有一个最短路径,取这两者的较小值就是答案了。

代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int N=2e5+10;
const int M=1e6+10;
const int inf=0x3f3f3f3f;
int n,m,k,a[N],vis[N],cnt,ds[N],dt[N];
vector<int> g[N];

void bfs(int s,int *dis){
    queue<int> que;
    dis[s]=0,que.push(s);
    while(!que.empty()){
        int u=que.front();que.pop();
        for(int v:g[u])
            if(dis[v]>dis[u]+1){
                dis[v]=dis[u]+1;
                que.push(v);
            }
    }
}

bool cmp(int x,int y){
    return ds[x]-dt[x]<ds[y]-dt[y];
}

int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1,x;i<=k;i++) scanf("%d",&a[i]);
    for(int i=1,u,v;i<=m;i++){
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    memset(ds,0x3f,sizeof(ds));
    memset(dt,0x3f,sizeof(dt));
    bfs(1,ds);bfs(n,dt);
    int ans=0,maxds=-inf;
    sort(a+1,a+k+1,cmp);
    for(int i=1;i<=k;i++){
        ans=max(ans,maxds+dt[a[i]]+1);
        maxds=max(maxds,ds[a[i]]);
    }
    printf("%d\n",min(ds[n],ans));
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BakaCirno/p/12431981.html
今日推荐