分析:
如何判断是不是 a->b
是不是最短路的一条路径?
- 看是否有 dist[a] == dist[b] + 1
, dist[a]
是从 a 到 终点 距离
小明从 a 走到 b ,
- 如果 a->b
不是当前最短路上的路径,则一定会重新规划路线 ( dist[a] < dist[b] + 1
则 mincnt ++, maxcnt ++
)
- 如果 a->b
是当前最短路上的路径( dist[a] == dist[b] + 1
)
- 如果 a 到重点最短路只有一条,不需要更新
- 如果多于一种走法, maxcnt ++
怎么判断在 y
点有几条最短路通向终点呢?
- 我们在求 dist
时是在反向图上跑 bfs
- 如跑 bfs 时,发现对于 x -> y
(注意是反向图,实际路径中是 y 指向 x)
- dist[y] > dist[x] + 1
第一次发现 y
的最短路,进行 cnt[y] = 1
- dist[y] == dist[x] + 1
不止第一次发现 y
的最短路,进行 cnt[y] ++
代码用y总的
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 200010, M = N;
int n, m;
int h[N], e[M], ne[M], idx;
int dist[N], cnt[N], q[N];
int path[N];
void add(int a, int b) // 添加一条边a->b
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
void bfs(int start)
{
int hh = 0, tt = 0;
memset(dist, 0x3f, sizeof dist);
dist[start] = 0;
q[0] = start;
while (hh <= tt)
{
int t = q[hh ++ ];
for (int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if (dist[j] > dist[t] + 1)
{
dist[j] = dist[t] + 1;
cnt[j] = 1;
q[ ++ tt] = j;
}
else if (dist[j] == dist[t] + 1)
cnt[j] ++ ;
}
}
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while (m -- )
{
int a, b;
scanf("%d%d", &a, &b);
add(b, a);
}
int k;
scanf("%d", &k);
for (int i = 1; i <= k; i ++ ) scanf("%d", &path[i]);
bfs(path[k]);
int minc = 0, maxc = 0;
for (int i = 1; i < k; i ++ )
{
int a = path[i], b = path[i + 1];
if (dist[a] < dist[b] + 1) minc ++, maxc ++ ;
else if (cnt[a] > 1) maxc ++ ;
}
printf("%d %d\n", minc, maxc);
return 0;
}
// 作者:yxc
// 链接:https://www.acwing.com/activity/content/code/content/1472463/
// 来源:AcWing
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。