最短路径生成树是一棵树,它的根节点为S,在这棵树上跑dijkstra与在原图上跑得到的d会是完全一样的。
这棵树的生成可以用dijkstra来理解。每个未被标记的节点把d推priority_queue,取出堆顶x,x先被标记。
然后更新与x相连的节点,如果有d[y]>d[x]+e[k].c,那么把y节点以及k这条边一起选入预定的最小路径生成树。
当y被标记时,这条预定的边变成实际的最小路径生成树的一条边。
再理解一下,dijkstra看似随机的从priority_queue中随机的取点,实际上它取的点还是有原则的。
画一个图出来,YY一下,可以发现dijkstra的扩展路径就是一棵树,
(很满足树的特性,一个点有很多个孩子节点,每个点只有一个父亲……)把这棵树提取出来便是最小路径生成树啦


其实这个不难想到,只是他会出一些结合的题,所以还是明确一下概念比较好

这是一个求最短路径树的方案数的题

#include<bits/stdc++.h>
#define inf 1e12;
using namespace std;

int n,m,x,y,z;
long long dis[1010][1010],g[20000],cnt[20000];
bool vis[2000000]={0};

int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= n;j++)//一、预处理 
        {
            if(i == j) dis[i][j]=0;
            else dis[j][i] = dis[i][j] = inf;
        }
    for(int i = 1;i <= m;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        if(dis[x][y] > z)
            dis[x][y] = dis[y][x] = z; 
    }
    for(int i = 1;i <= n;i++) g[i]=dis[1][i];
    
    for(int i = 1;i <= n;i++)// 二、用迪杰斯特拉算法求出一号房间到每个房间的单源最短路 
    {
        long long minn = inf;
        int u;
        for(int j = 1;j <= n;j++)
        {
            if(!vis[j] && minn > g[j])
            {
                minn = g[j];
                u = j;
            }
        }    //最小边
        vis[u] = 1;
        for(int j = 1;j <= n;j++)
            if(g[j] > dis[u][j] + g[u])
                g[j] = g[u] + dis[u][j];
    }
    long long ans = 1;
    for(int i = 1;i <= n;i++)//三、方案累加 
        for(int j = 1;j <= n;j++)
            if(i != j && g[j] == g[i] + dis[i][j]) 
                cnt[j]++;
    for(int i = 1;i <= n;i++)
    {
        if(cnt[i] == 0) continue;
        ans *= cnt[i];
        ans %= 2147483647;
    }
    printf("%lld\n",ans);
}