最短路径树小结

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最短路径树小结相关的知识,希望对你有一定的参考价值。

最短路径树小结

0.定义

原图的一个生成树,根到任意结点的路径等于原图的根到该节点的最短路。

c o s t S P T ≥ c o s t M S T cost_{SPT}\\ge cost_{MST} costSPTcostMST ,即 S P T SPT SPT 的权值和不一定是最优的。

S P T ≠ M S T SPT\\ne MST SPT=MST​​。

1.如何求SPT

采用 d i j k s t r a dijkstra dijkstra,同时维护一个 p r e [ u ] pre[u] pre[u] 数组,表示结点 u u u对应的父亲这条边的编号。

        for(register int i = head[u]; i != 0; i = edges[i].next) { // 找邻居 
            int next = edges[i].to;
            long long w = edges[i].w;
            if(dis[next] > dis[u] + w) { // 松弛操作 
                dis[next] = dis[u] + w;
                Node nxt = {next, dis[next]}; 
                pq.push(nxt);
                pre[next] = i;
            }
            if(dis[next] == dis[u] + edges[i].w && edges[i].w < edges[pre[next]].w) {
                pre[next] = i;
            }
        }

1.习题

CF545E Paths and Trees

输出 S P T SPT SPT的权值和 和 边。

板题

#include<bits/stdc++.h>

using namespace std;

inline int read() {
    int x = 0, f = 1;
    char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') {
            f = -1;
        }
        c = getchar();
    }
    while(c <= '9' && c >= '0') {
        x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    }
    return x * f;
}

const long long INF = 0x3f3f3f3f3f3f3f3f;
const int Maxn = 3e5 + 5;
const int Maxm = 6e5 + 5;

int n, m, s, cnt = 1, head[Maxn], pre[Maxn];

long long dis[Maxn], ans[Maxn];

bool vis[Maxn];

struct Line { // to指向的点, w是边权, next是这一条边连接的下一条边是谁
    int to;
    int w;
    long long next;
} edges[Maxm]; // 存所有的边 

inline void Add(int a, int b, long long w) { // 添加边的函数
    ++cnt; // 边的编号 
    edges[cnt].to = b; // 第cnt条边指向点y 
    edges[cnt].w = w; // 第cnt条边的权值 
    edges[cnt].next = head[a]; // 第cnt条边的指向连接点x的第一条边 
    head[a] = cnt; // 将连接点x的第一条边更新为第cnt条边
    return ;
}

struct Node {
    int id;
    long long dist;
    bool operator < (const Node &cur) const {
        return dist > cur.dist;
    }
} ;

inline void Dijkstra(int start) {
    priority_queue <Node> pq; // 优先队列维护当前权值最小 
    for(register int i = 1; i <= n; ++i) {
        dis[i] = INF; // DP初始化 
        vis[i] = false;
    }
    dis[start] = 0; // DP的边界条件 
    Node Start = {s, 0};
    pq.push(Start); // 确定源点到源点的最短路径 将源点放入优先队列进行广搜 
    while(!pq.empty()) {
        Node now = pq.top();
        pq.pop();
        int u = now.id; // 中转点
        if(vis[u] == true) {
            continue; // 防止多次将一个点加入堆中 
        }
        vis[u] = true;
        for(register int i = head[u]; i != 0; i = edges[i].next) { // 找邻居 
            int next = edges[i].to;
            long long w = edges[i].w;
            if(dis[next] > dis[u] + w) { // 松弛操作 
                dis[next] = dis[u] + w;
                Node nxt = {next, dis[next]}; 
                pq.push(nxt);
                pre[next] = i;
            }
            if(dis[next] == dis[u] + edges[i].w && edges[i].w < edges[pre[next]].w) {
                pre[next] = i;
            }
        }
    }
    return ;
}

signed main() {
    n = read(), m = read();
    for(register int i = 1; i <= m; ++i) { // m条边
        int x = read(), y = read();
        long long w = read();
        Add(x, y, w), Add(y, x, w); // 双向边 
    }
    s = read();
    Dijkstra(s);
    long long sum = 0, tot = 0;
    for(register int i = 1; i <= n; ++i) {
        if(i == s) {
            continue; // 源点到自己无边
        }
        int id = pre[i];
        long long w = edges[id].w;
        sum += w;
        ans[++tot] = id; // 记录边的编号
    }
    sort(ans + 1, ans + tot + 1);
    printf("%lld\\n", sum);
    for(register int i = 1; i <= tot; ++i) { // 向下取整
        printf("%lld ", ans[i]>>1);
    }
    puts("");
    return 0;
}

CF545E Paths and Trees

显然删到 ≤ n − 1 \\le n-1 n1 条边是最好的。

先确定 S P T SPT SPT,然后 d f s dfs dfs扫一遍,每扫到一个边就 c n t + + cnt++ cnt++ c n t = k cnt=k cnt=k 直接返回。

#include<bits/stdc++.h>

using namespace std;

#define int long long // 坏习惯...

inline int read() {
    int x = 0, f = 1;
    char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') {
            f = -1;
        }
        c = getchar();
    }
    while(c <= '9' && c >= '0') {
        x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
    }
    return x * f;
}

const int INF = 0x3f3f3f3f3f3f3f3f;
const int Maxn = 3e5 + 5;
const int Maxm = 6e5 + 5;

int n, m, s, k, cnt=1, sum, head[Maxn], dis[Maxn], pre[Maxn];

bool vis[Maxn], ins[Maxm];

struct Line {
    int to;
    int w;
    int next;
} edges[Maxm];

inline void Add(int a, int b, int w) {
    ++cnt;
    edges[cnt].to = b;
    edges[cnt].w = w;
    edges[cnt].next = head[a];
    head[a] = cnt;
    return ;
}

struct Node {
    int id;
    int dist;
    inline bool operator < (const Node &cur) const {
        return dist > cur.dist;
    }
} ;

void Dijkstra(int start) {
    priority_queue <Node> pq;
    for(register int i = 1; i <= n; ++i) {
        dis[i] = INF;
        vis[i] = false;
    }
    dis[start] = 0;
    Node Start = {start, 0};
    pq.push(Start);
    while(!pq.empty()) {
        Node now = pq.top();
        pq.pop();
        int u = now.id;
        if(vis[u] == true) {
            continue;
        }
        vis[u] = true;
        for(register int i = head[u]; i != 0; i = edges[i].next) {
            int next = edges[i].to, w = edges[i].w;
            if(dis[next] - dis[u] > w) {
                dis[next] = dis[u] + w;
                Node nxt = {next, dis[next]};
                pq.push(nxt);
                pre[next] = i;
            }
            if(dis[next] == dis[u] + edges[i].w && edges[i].w < edges[pre[next]].w) {
                pre[next] = i;
            }
        }
    }
    for(register int i = 1; i <= n; ++i) {
        vis[i] = false;
    }   
    return ;
}

void DFS(int x, int father) {
    if(sum == k) {
        puts("");
        exit(0);
    }
    for(register int i = head[x]; i != 0; i = edges[i].next) {
        int next = edges[i].to, w = edges[i].w;
        if(next == father) {
            continue;
        }
        if(pre[next] == i) {
            ++sum;
            vis[next] = true;
            printf("%d ", i>>1);
            DFS(next, x);
        }
    }
    return ;    
}

signed main() {
    n = read(), m = read(), k = read()bzoj4016 [FJOI2014]最短路径树问题

BZOJ4016[FJOI2014]最短路径树问题 最短路径树+点分治

P2993 [FJOI2014]最短路径树问题

最短路径树

BZOJ 4016 [FJOI2014]最短路径树问题

BZOJ 4016: [FJOI2014]最短路径树问题( 最短路 + 点分治 )