AcWing 3772. 更新线路(BFS)

小白刷题中
做一道BFS的题,参考https://www.acwing.com/video/3312/

题意

给定一条路径,小明沿着路径走。导航软件会给小明推荐最短路径。
首先,在点 s 处,导航软件会找到并显示出一条从点 s 到点 t 的最短路径。
如果小明的行进线路恰好与软件推荐线路一致,则软件推荐线路将不会发生任何改变。
但是,如果小明在某一点处,行进线路与软件推荐线路发生了分歧,例如,软件推荐前往点 v,小明却前往了点 w。
那么,在他到达点 w 后,软件就会实时更新推荐线路,即找到并显示出一条从点 w 到点 t 的最短路径。
导航软件会一直工作到小明到达点 t 为止,在这一过程中,软件的提供线路可能会经过若干次更新。
由于软件在推荐最短路径时具有随机性,所以在整个行进过程中,软件更新推荐线路的次数并不确定。
现在,给定有向图和行进路线,请你求出软件更新推荐线路的最小可能次数和最大可能次数。

输入输出

输入:第一行包含两个整数 n 和 m。
接下来 m 行,每行包含两个整数 u,v,表示存在一条从点 u 到点 v 的有向边。
随后一行包含一个整数 k。
最后一行包含 k 个整数 p1,p2,…,pk。
输出:一行,空格隔开的两个整数,表示软件更新推荐路线的最小可能次数和最大可能次数。

思路

小明走的路径中,如果a->b不在一条最短路径中,那么最小可能次数和最大可能次数都要加一;
如果a->b在一条最短路径中,分情况讨论:1.a只能走b,导航就不需要更新;2.a还能走别的最短路径,那么最大推荐次数加一,最小推荐次数不变。
用bfs来更新给个点到给出路径终点的最短路径,以给出路径的终点作为bfs的起点,建立反向边,更新每个点的最短路径。同时还可以记录每个点有多少条出边。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 200010;
int tot;
int head[N],ver[N],nxt[N];  //建邻接表需要的数组
int dist[N],cnt[N];
int path[N];    //路径
int q[N];   //队列

void add(int u, int v)  // 添加一条边u->v
{
    ver[++tot] = v;
    nxt[tot] = head[u];
    head[u] = tot;
}

void bfs(int start){    //计算每个点到终点的最短路径长度,同时记录下每个点在最短路上出边的数量
    int hh=0, tt=0; //hh为遍历队列的指针,tt为队尾指针
    memset(dist, 0x3f, sizeof dist);    //初始化为无穷大
    q[0] = start;   //先将起点入队列
    dist[start] = 0;
    while(hh <= tt){
        int u = q[hh++];
        for(int i = head[u]; i;i = nxt[i]){ //遍历u的所有邻接点
            int v = ver[i];
            if(dist[v] > dist[u] + 1){
                dist[v] = dist[u] + 1;
                cnt[v]++;
                q[++tt] = v;
            }
            else if(dist[v] == dist[u] + 1){
                cnt[v]++;
            }
        }
    }
}

int main()
{
    int n,m,k;
    cin >> n >> m;
    for (int i = 0; i < m; i ++ ){
        int u,v;
        cin >> u >> v;
        add(v,u);   //建立反向边,因为要计算每个点到终点的最短路
    }
    cin >> k;
    for (int i = 1; i <= k; i ++ ) cin >> path[i];
    bfs(path[k]);
    int minc=0,maxc=0;
    for(int i = 1;i < k;i++){
        int u=path[i],v=path[i+1];  //遍历给出路径上的点
        if(dist[u] < dist[v] + 1){
            minc++;maxc++;
        }
        else if(dist[u] == dist[v] + 1){
            if(cnt[u] > 1) maxc++;
        }
    }
    cout << minc << " " << maxc;
    return 0;
}

posted @ 2021-07-18 15:36  inss!w!  阅读(46)  评论(0编辑  收藏  举报