知道黑暗城堡有 N 个房间, M 条能够制造的双向通道,以及每条通道的长度。php
城堡是树形的而且知足下面的条件:ios
设$ D_i$为若是全部的通道都被修建,第 i 号房间与第 1 号房间的最短路径长度;git
而 \(S_i\) 为实际修建的树形城堡中第$ i$ 号房间与第$ 1 $号房间的路径长度;算法
要求对于全部整数 \(i(1≤i≤N)\),有$ S_i=D_i$ 成立。数组
你想知道有多少种不一样的城堡修建方案。固然,你只须要输出答案对 \(2^{31}−1\) 取模以后的结果就好了。spa
第一行为两个由空格隔开的整数 \(N,M\);
第二行到第 \(M+1\) 行为 \(3\) 个由空格隔开的整数$ x,y,l$:表示 \(x\) 号房间与$ y$ 号房间之间的通道长度为 \(l\)。code
一个整数:不一样的城堡修建方案数对\(2^{31}-1\) 取模以后的结果。ip
4 6 1 2 1 1 3 2 1 4 3 2 3 1 2 4 2 3 4 1
6
样例说明get
一共有$ 4$ 个房间,\(6\) 条道路,其中 1 号和$ 2$ 号,$ 1 $号和 3 号,\(1\) 号和 \(4\) 号,\(2\) 号和$ 3$ 号,\(2\) 号和 $4 $号,\(3\) 号和 \(4\) 号房间之间的通道长度分别为$ 1,2,3,1,2,1。$string
而不一样的城堡修建方案数对 $2^{31}−1 $取模以后的结果为 \(6\)。
数据范围:
对于所有数据,\(1≤N≤1000,1≤M≤ \dfrac{N(N-1)}{2},1≤l≤200。\)
先用\(dijkstra\)求出1号房间到每一个房间的单源最短路径存储到\(dis\)数组中。把树形城堡看做以1为根的有根树。由题,若\(x\)是\(y\)的根节点,\(x、y\)之间的通道长度为\(z\),则应该有:\(dis[y]=dis[x]+z\)。事实上,咱们把知足题目要求的树结构,即对任意一对父子结点\(x、y\)都有上式成立的树结构,称为图的一棵最短路径生成树。与\(Prim\)算法相似,统计有多少结点\(x\)知足\(dis[p]=dis[x]+e[x][p]\),让\(p\)与其中任意一个x相连都符合题目要求。
最短路径生成树:对于任意一对父子结点\(x、y\)均知足\(dis[y]=dis[x]+e[x][y]\)的树结构称为图的一棵最短路径生成树;
在宏定义中!! \(2^{31-1}\) 写为 \((1<<31)-1\) 要加括号!! 要加括号!! 否则就会\(wa\)好多好屡次了...
而后,不要忘了给\(e\)数组初始化....否则就默认为0了..
这题数据范围比较小,因此能够用邻接矩阵,不过这个是树,稀疏图,通常是用邻接表的。
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<string> #include<algorithm> #include<iomanip> #include<cstdlib> #include<queue> #include<map> #include<set> #include<stack> #include<vector> #define ll long long using namespace std; inline ll read() { ll s=0,w=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();} while(isdigit(ch)) s=s*10+ch-'0',ch=getchar(); return s*w; } int n,m; ll dis[1010][1010],g[20000],cnt[20000]; bool vis[2000000]={0}; int main() { n=read(),m=read(); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)//1.预处理 if(i==j) dis[i][j]=0; else dis[j][i]=dis[i][j]=1e18; for(int i=1,x,y,z;i<=m;i++) { x=read(),y=read(),z=read(); 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++)//2.用dijkstra算法求出一号房间到每一个房间的最短路 { ll minn=1e18,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]; } ll ans=1; for(int i=1;i<=n;i++)//3.方案累加 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]) ans*=cnt[i],ans%=2147483647; printf("%lld",ans); return 0; }