最短路树

思路

对于最短路树上的任意非根节点 \(u\)​,\(dist(root,u)=\)\(root\)​ 到 \(u\)​​​ 的最短路。最短路树上的边一般是正权值的,因为如果是负权值好像建树的复杂度就高达 \(O(n^3)\) 了,因为 \(dijkstra\) 无法保证正确性,而 \(floyd\)\(O(n^3)\) 的, \(SPFA\) 则是可以退化到 \(O(nm)\) 的。

构造时,跑一遍 \(dijkstra\)​,连边更新信息的两个点建树即可,\(root\) 即为出发点 \(u\)​。很容易就可以理解这样会建成一棵树,因为一个点只会被更新一次。

最短路树一般用于最短路问题中有删边的问题。

例题一:\(CF1076D Edge Deletion\)

思路

问留下 \(k\) 条边以后最短路不变的点最多的情况。很容易想到用 \(root=1\) 的情况下构建一棵最短路树,然后只需要 \(n-1\) 条边就可以保证 \(n\) 个点的最短路不变。\(dfs\)\(1\) 号节点开始记录一个 \(cnt\),只要 \(cnt\leq k\) 的就输出这条边,否则就直接 \(return\)

\(Code\)

#include<bits/stdc++.h>
using namespace std;

int n, m, k;
int head[300005], e[600005], ne[600005], idx;
long long val[600005];
int pre[300005];
long long dist[300005];
bool vis[300005];
long long x, y, z;
int tot;

struct node{
	long long d;
	int p;
	inline bool operator <(const node&a)const{
		return d>a.d;
	}
};

template<typename T>
inline void read(T&x){
	x = 0; char q; bool f = 1;
	while(!isdigit(q = getchar()))	if(q == '-')	f = 0;
	while(isdigit(q))	x = (x<<1) + (x<<3) + (q^48), q = getchar(); 
	x = f?x:-x;
}

template<typename T>
inline void write(T x){
	if(x < 0)	x = -x, putchar('-');
	if(x > 9)	write(x/10);
	putchar(x%10^48);
}

inline void add(int u, int v, long long num){
    e[++idx] = v, ne[idx] = head[u], val[idx] = num, head[u] = idx;
}

inline void dijkstra(){
	priority_queue<node>q;
    memset(dist, 0x7f, sizeof(dist));
    q.push((node){0, 1});
	dist[1] = 0;
    while(!q.empty()){
        int u = q.top().p;
		q.pop();
        if(vis[u])	continue;
        vis[u] = 1;
        for(register int i = head[u]; i; i = ne[i]){
            int v = e[i];
            if(dist[v] >= dist[u]+val[i]){
                dist[v] = dist[u]+val[i];
                q.push((node){dist[v], v});
                pre[v] = i;
            }
        }
    }
}

inline void dfs(int u){
	for(register int i = head[u]; i; i = ne[i]){
		int v = e[i];
		if(i == pre[v]){
			tot++;
			if(tot > k || tot == n)	exit(0);
			write(i+1>>1);
			putchar(' ');
			dfs(v);
		}
	}
}

int main(){
	read(n), read(m), read(k);
    for(register int i = 1; i <= m; ++i){
		read(x), read(y), read(z);
        add(x, y, z);
		add(y, x, z);
    }
    dijkstra();
    write(min(n-1, k));
    puts("");
    dfs(1);
    return 0;
}
posted @ 2024-10-09 18:28  Zzzzzzzm  阅读(11)  评论(0)    收藏  举报