其他分享
首页 > 其他分享> > [暑假集训Day1T1]黑暗城堡

[暑假集训Day1T1]黑暗城堡

作者:互联网

因为D[i]表示i号节点到1号节点的最短路径,所以可以先以1为源点跑一边SPFA,预处理出每个点到1号节点的最短路。之后开始考虑所谓的“最短路径生成树”,在这棵生成树中有以下性质:当fa[i]==node时,必满足dist[node]+w(node,i)=dist[node],但dist[node]+w(node,i)==dist[node]时,node不一定是i的父节点,因为图的最短路可能有多条。因此我们记录mul[i]为i的前驱个数,也就是所有满足dist[k]+w(k,i)==dist[i]的点的个数。根据乘法原理累计相乘即可求出答案。

常见疑问:
Q1:为什么这样构造出来一定是一棵树???

A1:因为对于每一棵生成树,除1号节点外,都有一个唯一的前驱,我们假想他们之间连了一条边,则连了(n-1)条边,并且保证联通性,根据树的定义,可以保证这是一棵树。

Q2:为什么可以不排序???网上大神排序出于什么目的???

A2:因为边权均为正,所以比较dist值较大的节点只能从dist值较小的节点走过来,因此对i号节点统计时我们是用不到dist值比i大的节点的,因此使用O(NlogN)的时间按每个节点dist值进行排序,即可省去一半的时间。注意,不排序对正确性没有影响。

Q3:为什么不用伟大的Dijkstra堆优化而使用已经死了的SPFA???

A3:LQX学长调他的堆优化调了一个下午。

参考代码如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#define int long long
#define mod 2147483647
#define N 1005
#define M 1000005
#define INF 110412365
using namespace std;
struct node
{
    int num,dist;
}point[N];
int n,m,v[M],w[M],head[M],nxt[M],cnt,x,y,z,mul[N];
bool vis[N];
void add(int a,int b,int c)
{
    v[++cnt]=b;
    w[cnt]=c;
    nxt[cnt]=head[a];
    head[a]=cnt;
}
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
    return x*f;
}
void spfa(int s)
{
    for(int i=2;i<=n;i++)point[i].dist=INF;
    queue<int>q;
    q.push(s);
    vis[s]=1;
    while(!q.empty())
    {
        int c=q.front();
        q.pop();
        vis[c]=0;
        for(int i=head[c];i;i=nxt[i])
        {
            int y=v[i];
            if(point[y].dist>point[c].dist+w[i])
            {
                point[y].dist=point[c].dist+w[i];
                if(!vis[y])
                {
                    q.push(y);
                    vis[y]=1;
                }
            }
        }
    }
}
bool cmp(node a,node b)
{
    return a.dist<b.dist;
}
signed main()
{
    n=read();m=read();
    for(int i=1;i<=m;i++)
    {
        x=read();y=read();z=read();
        add(x,y,z);add(y,x,z);
    }
    spfa(1);
    for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j;j=nxt[j])
        {
            if(point[i].dist+w[j]==point[v[j]].dist)mul[v[j]]++;
        }
    }
    int ans=1;
    for(int i=2;i<=n;i++)ans*=mul[i],ans%=mod;
    cout<<ans<<endl;
    return 0;
}

  

 

标签:node,cnt,ch,dist,Day1T1,节点,int,暑假,集训
来源: https://www.cnblogs.com/szmssf/p/11153996.html