16.1113 模拟考试T3

城堡
【问题描述】
给定一张N个点M条边的无向连通图,每条边有边权。我们需要从M条边中
选出N − 1条, 构成一棵树。 记原图中从 1 号点到每个节点的最短路径长度为?Di ,
树中从 1 号点到每个节点的最短路径长度为Si ,构出的树应当满足对于任意节点
i,都有Di = Si 。
请你求出选出N − 1条边的方案数。
【输入格式】
输入的第一行包含两个整数N和M。
接下来M行,每行包含三个整数u、v和w,描述一条连接节点u和v且边权为
w的边。
【输出格式】
输出一行,包含一个整数,代表方案数对2^31 − 1取模得到的结果。
【样例输入】
3 3
1 2 2
1 3 1
2 3 1
【样例输出】
2
【数据规模和约定】
对于30%的数据 2 ≤ N ≤ 5,M ≤ 10。
对于50%的数据,满足条件的方案数不超过 10000。
对于100%的数据,2≤ N ≤ 1000,N − 1 ≤ M ≤
N(N−1)/2,
1 ≤ w ≤ 100。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cstdlib>
 4 #include<queue>
 5 using namespace std;
 6 typedef long long ll;
 7 const int N=1000;
 8 const int M=499500;
 9 const int INFI=12345678;
10 const ll mod = (1LL<<31)-1LL;
11 struct node{
12     int next,node,w;
13 }e[M*2];
14 ll c[N+1],ans;
15 int n,m,x,y,w,head[N+1],tot,dis[N+1];
16 bool exist[N+1];
17 void add_edge(int a,int b,int w){
18     e[++tot].next=head[a];
19     head[a]=tot;e[tot].node=b;e[tot].w=w;
20 }
21 inline void SPFA(int s)
22 {
23     queue<int> que;
24     for(int i=1;i<=n;i++) dis[i]=0x3f;
25     dis[s]=0;exist[s]=true;que.push(s);
26     while(!que.empty())
27     {
28         int cur=que.front();
29         exist[cur]=false;que.pop();
30         for(int i=head[cur];i;i=e[i].next)
31         {
32             int node=e[i].node;
33             if(dis[node]>dis[cur]+e[i].w){
34                 dis[node]=dis[cur]+e[i].w;
35                 if(!exist[node])
36                   exist[node]=true,que.push(node);
37             }
38         }
39     }
40 }
41 int main()
42 {
43     freopen("castle.in","r",stdin);
44     freopen("castle.out","w",stdout);
45     scanf("%d%d",&n,&m);
46     for(int i=1;i<=m;i++){
47         scanf("%d%d%d",&x,&y,&w);add_edge(x,y,w);add_edge(y,x,w);
48     }
49     SPFA(1);
50     queue<int> q;q.push(1),exist[1]=true,c[1]=1LL;
51     while(!q.empty()){
52         int cur=q.front();q.pop();
53         for(int i=head[cur];i;i=e[i].next){
54             int node=e[i].node;
55             if(dis[node]==dis[cur]+e[i].w){
56                 ++c[node];
57                 if(c[node]>=mod) c[node]-=mod;
58                 if(!exist[node]) q.push(node),exist[node]=true;    
59             }
60         }
61     }
62     ans=1LL;
63     for(int i=1;i<=n;i++){
64         ans*=c[i];
65         if(ans>=mod) ans%=mod;
66     }
67     printf("%d",(int)ans);
68     fclose(stdin);
69     fclose(stdout);
70     return 0;
71 }

思路:两遍SPFA,第一遍求出dis[],第二遍的时候求出没个点可以有几条最短路得来,(++c[i]),之后,根据乘法原理,c数组全部乘起来并且取模。

原文地址:https://www.cnblogs.com/suishiguang/p/6058828.html