黑暗城堡

ttps://loj.ac/problem/10064

题目描述

  给出一张图,求它最短路径树的个数。

思路

  最短路径树就是对于根节点\(u\),它到任意\(v\)的最小距离等于树上的距离。我们考虑\(dijkstra\)的过程,每一次选择一个与起始节点距离最小的点加入已确定的集合,所以我们每次选择的边组成的集合就是一种最短路径树。至于统计方案,在进行\(dijkstra\)的时候,我们可以判断每一条边,如果\(dis[v]=dis[u]+e[i]\)方案数可以累乘,不过如果更新\(dis\)需要重置到这一点的最短路方案数。当然我们也可以在跑完\(dijkstra\)后统计答案。

代码

#include <bits/stdc++.h>
using namespace std;
const long long mod=2147483647;
const int MAXN=1005,MAXM=5e5+10;
int head[MAXN],nxt[MAXM*2],to[MAXM*2],w[MAXM*2],tot;
int dis[MAXN];
bool vis[MAXN];
void add_edge(int x,int y,int z)
{
    nxt[++tot]=head[x];
    head[x]=tot;
    to[tot]=y;
    w[tot]=z;
}
priority_queue<pair<int,int> >q;
int main() 
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        add_edge(x,y,z);
        add_edge(y,x,z);
    }
    memset(dis,0x3f,sizeof(dis));
    dis[1]=0;
    q.push(make_pair(0,1)); 
    while(!q.empty())
    {
        int x=q.top().second;q.pop();
        if(vis[x])continue ;
        vis[x]=1;
        for(int i=head[x];i;i=nxt[i])
        {
            int y=to[i],v=w[i];
            if(dis[y]>dis[x]+v)
            {
                dis[y]=dis[x]+v;
                q.push(make_pair(-dis[y],y));
            }
        }
    }
/*    for(int i=1;i<=n;i++)
        printf("%d ",dis[i]);
    printf("\n");*/
    long long ans=1;
    for(int i=1;i<=n;i++)
    {
        long long s=0;
        for(int j=head[i];j;j=nxt[j])
        {
            int k=to[j],v=w[j];
            if(dis[i]==dis[k]+v)
                s++;
        }
//        cout<<s<<' '<<ans<<endl;
        if(s!=0)ans=(ans*s)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2019-11-04 20:57  fbz  阅读(130)  评论(0编辑  收藏  举报