zoukankan      html  css  js  c++  java
  • [暑假集训Day1T1]黑暗城堡

    因为D[i]表示i号节点到1号节点的最短路径,所以可以先以1为源点跑一边SPFA,预处理出每个点到1号节点的最短路。之后开始考虑所谓的“最短路径生成树”,在这棵生成树中有以下性质:当fa[i]==node时,必满足dist[node]+w(node,i)=dist[i],但是dist[node]+w(node,i)==dist[i]时,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学长调他的堆优化调了一个下午。

    参考代码如下:

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<cstdio>
     4 #include<queue>
     5 #define int long long
     6 #define mod 2147483647
     7 #define N 1005
     8 #define M 1000005
     9 #define INF 110412365
    10 using namespace std;
    11 struct node
    12 {
    13     int num,dist;
    14 }point[N];
    15 int n,m,v[M],w[M],head[M],nxt[M],cnt,x,y,z,mul[N];
    16 bool vis[N];
    17 void add(int a,int b,int c)
    18 {
    19     v[++cnt]=b;
    20     w[cnt]=c;
    21     nxt[cnt]=head[a];
    22     head[a]=cnt;
    23 }
    24 int read()
    25 {
    26     int x=0,f=1;char ch=getchar();
    27     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    28     while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
    29     return x*f;
    30 }
    31 void spfa(int s)
    32 {
    33     for(int i=2;i<=n;i++)point[i].dist=INF;
    34     queue<int>q;
    35     q.push(s);
    36     vis[s]=1;
    37     while(!q.empty())
    38     {
    39         int c=q.front();
    40         q.pop();
    41         vis[c]=0;
    42         for(int i=head[c];i;i=nxt[i])
    43         {
    44             int y=v[i];
    45             if(point[y].dist>point[c].dist+w[i])
    46             {
    47                 point[y].dist=point[c].dist+w[i];
    48                 if(!vis[y])
    49                 {
    50                     q.push(y);
    51                     vis[y]=1;
    52                 }
    53             }
    54         }
    55     }
    56 }
    57 bool cmp(node a,node b)
    58 {
    59     return a.dist<b.dist;
    60 }
    61 signed main()
    62 {
    63     n=read();m=read();
    64     for(int i=1;i<=m;i++)
    65     {
    66         x=read();y=read();z=read();
    67         add(x,y,z);add(y,x,z);
    68     }
    69     spfa(1);
    70     for(int i=1;i<=n;i++)
    71     {
    72         for(int j=head[i];j;j=nxt[j])
    73         {
    74             if(point[i].dist+w[j]==point[v[j]].dist)mul[v[j]]++;
    75         }
    76     }
    77     int ans=1;
    78     for(int i=2;i<=n;i++)ans*=mul[i],ans%=mod;
    79     cout<<ans<<endl;
    80     return 0;
    81 }
    View Code

     

  • 相关阅读:
    Hibernate(2)——Hibernate的实现原理总结和对其模仿的demo
    Hibernate(1)——数据访问层的架构模式
    JVM学习(4)——全面总结Java的GC算法和回收机制
    JVM学习(3)——总结Java内存模型
    JVM学习(2)——技术文章里常说的堆,栈,堆栈到底是什么,从os的角度总结
    JVM学习(1)——通过实例总结Java虚拟机的运行机制
    减小内存的占用问题——享元模式和单例模式的对比分析
    继承、组合和接口用法——策略模式复习总结
    软件工程的引入:Scrum开发框架总结
    软件工程里的UML序列图的概念和总结
  • 原文地址:https://www.cnblogs.com/szmssf/p/11153996.html
Copyright © 2011-2022 走看看