题目
分析
首先考虑离0点最近的那个点,一定和0点只连着一条边,则这条边是必选的;然后考察第二近的点,一种可能是和0点直接连的边比较近,一种可能是经过刚才最近的那个点再到0点的路比较近,不管是哪一种,选择都是唯一的,而剩下第三种可能是两者距离相同,这样的话两者选且只能选一个。以此类推,假设现在已经构造好了前k个点的一棵子树,看剩余点中到0点最近的点,这个点到0点有k种方法(分别是和那k个点连边),其中有m个是可以保持最短距离的,则这一步可选的边数就是m。一直构造,把方法数累乘,就能得到最后的结果。整个过程可以很好的符合dijkstra的过程,而生成树的步骤和prim如出一辙。
代码
1 //#pragma GCC optimize(2)
2 #include<iostream>
3 #include<queue>
4 #include<cstdio>
5 #include<cstring>
6 using namespace std;
7 struct sb
8 {
9 int to,nx,w;
10 }g[1001000];
11 int cnt,list[1001];
12 void add(int x,int y,int w)
13 {
14 g[++cnt].to=y; g[cnt].nx=list[x]; g[cnt].w=w; list[x]=cnt;
15 g[++cnt].to=x; g[cnt].nx=list[y]; g[cnt].w=w; list[y]=cnt;
16 }
17 int dis[1001],vis[1001],d[1001];
18 queue<int> q;
19 void spfa()
20 {
21 dis[1]=0; vis[1]=1;
22 q.push(1);
23 while (!q.empty())
24 {
25 int x=q.front(); q.pop(); vis[x]=0;
26 for (int i=list[x];i;i=g[i].nx)
27 {
28 int y=g[i].to;
29 if (dis[x]+g[i].w<dis[y])
30 {
31 dis[y]=dis[x]+g[i].w;
32 d[y]=1;
33 if (!vis[y])
34 {
35 vis[y]=1;
36 q.push(y);
37 }
38 }
39 else if (dis[x]+g[i].w==dis[y]) d[y]++;
40 }
41 }
42 }
43 int main ()
44 {
45 int n,m;
46 cin>>n>>m;
47 for (int i=1,x,y,z;i<=m;i++)
48 {
49 scanf("%d%d%d",&x,&y,&z);
50 add(x,y,z);
51 }
52 for(int i=1;i<=n;i++) dis[i]=1000000000;
53 spfa();
54 long long ans=1;
55 for (int i=2;i<=n;i++)
56 ans=(ans*d[i])%2147483647;
57 cout<<ans;
58 }