最短路径树
最短路径树:从根节点出发,在树中到任意结点的路径均为最短路径。可以通过在做 Dij 过程中记录每个点的前驱点得到。
性质:从根节点出发,到所有点的距离总和最小。
若还要保证最短路径树的总边权和最小,需要注意一点:若某次松弛前的结果与松弛后的结果相等 (即 \(dist_{v} = dist_{u} + w\)),并且当前这条前驱边的边权 \(w\) 比之前的前驱边边权更小,则需要更新 \(v\) 的前驱边 \(pre_{v}\) 为这条新的前驱边。在代码中为了简洁,只需要将 if 中的判断条件 \(dist_{v} > dist_{u} + w\) 改为 \(\ge\) 就行了。
CF545E(模板)
struct Edge{
int u, v, w;
}edges[300005];
int n, m, root;
vector<array<int,3>> G[300005];
bool st[300005];
ll dist[300005];
pii pre[300005]; // 除root外均有值,(pre[u], u) 即为最短路树上的边
void solve()
{
cin >> n >> m;
for(int i = 1; i <= m; i ++){
int u, v, w;
cin >> u >> v >> w;
edges[i] = {u, v, w};
G[u].pb({v, w, i}); G[v].pb({u, w, i});
}
cin >> root;
memset(dist, 0x3f, sizeof dist);
dist[root] = 0;
priority_queue<pli,vector<pli>,greater<pli>> pq;
pq.push({0, root});
while(pq.size()){
auto [dis, u] = pq.top();
pq.pop();
if(st[u]) continue;
st[u] = true;
for(auto &[v, w, id] : G[u]){
if(dist[v] >= dist[u] + w){
dist[v] = dist[u] + w;
pre[v] = {u, id};
pq.push({dist[v], v});
}
}
}
CF1076D
留下的边显然应该在最短路树上,且与根节点 \(1\) 连通。求出最短路树后,从 \(1\) 出发 dfs,找够 \(k\) 条边就停止继续找就可以了。
CF1005F
给定一张边权均为 \(1\) 的无向图,求最短路径树的方案数,并输出不超过 \(k\) 种方案。
只需要将维护每个点的前驱边改为维护前驱边集合就行了,这样总方案数即为所有点的前驱边集合大小的乘积(每种方案相当于每个点选前驱点集合中的某一个),然后采用 dfs 枚举循环的方式找方案,找够了 \(k\) 种方案就退出。

浙公网安备 33010602011771号