Atcoder abc218_f Blocked Roads 题解

题目链接

传送门

题目大意

给定一个有向图,对于每条边,求出删除这条边后点 \(1\) 到点 \(n\) 的最短路长度,若无法到达输出 \(-1\)

思路分析

朴素的思想是对于每条边跑一边 bfs,时间复杂度为 \(O(m\times(n+m))=O(m^2)\),会超时。我们应减少跑 bfs 的次数。

由于在图中,最短路所经过的边数不可能超过 \(n-1\),否则一个点就会经过两次。所以我们可以记录从点 \(1\) 到点 \(n\) 的最短路所经过的边,而后枚举每条边,若此边不在最短路中,则直接输出原来的最短路长度,否则单独跑一遍 bfs。时间复杂度为 \(O(n+m+(n-1)\times(n+m))=O(nm)\)

代码精讲

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii; // 结构体会超时

const int N=405,M=1.6e5+10;
int n,m;
int dis[N],pre[N];
vector<int> f[N];
pii edges[M];

void bfs(pii del){ // 最短路
    memset(dis,-1,sizeof dis);
    queue<int> q;
    q.push(1),dis[1]=0;
    while (!q.empty()){
        int u=q.front();
        q.pop();
        for (auto v:f[u]){
            if (del==make_pair(u,v)) continue;
            if (dis[v]==-1) q.push(v),dis[v]=dis[u]+1,pre[v]=u;
        }
    }
}
int main(){
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;++i){
        int u,v;
        scanf("%d%d",&u,&v);
        f[u].push_back(v);
        edges[i]={u,v};
    }
    bfs({0,0});
    set<pii> st; // 存储最短路上的边
    int p=n,len=dis[n];
    while (pre[p]!=0){
        st.insert({pre[p],p});
        p=pre[p];
    }
    for (int i=1;i<=m;++i){
        if (st.count(edges[i])){
            bfs(edges[i]);
            printf("%d\n",dis[n]);
        }else printf("%d\n",len);
    }
    return 0;
}
posted @ 2025-10-08 11:37  CodingJuRuo  阅读(10)  评论(0)    收藏  举报