【问题描述】
给定一张n个点m条边的无向连通图,每条边有边权。我们需要从m条边中
选出n− 1条, 构成一棵树。 记原图中从 1 号点到每个节点的最短路径长度为Di ,
树中从 1 号点到每个节点的最短路径长度为Si ,构出的树应当满足对于任意节点
i都有Di= Si。请你求出选出n − 1条边的方案数。
【输入格式】
输入的第一行包含两个整数?和?。
接下来?行,每行包含三个整数?、?和?,描述一条连接节点?和?且边权为
?的边。
【输出格式】
输出一行,包含一个整数,代表方案数对2 ^31− 1取模得到的结果。
【样例输入】
3 3
1 2 2
1 3 1
2 3 1
【样例输出】
2
【数据规模和约定】
2 ≤ N ≤ 5,M ≤ 10。
对于50%的数据,满足条件的方案数不超过 10000。
对于100%的数据,2≤ N ≤ 1000,N − 1 ≤M ≤N*(N-1)/2,1 ≤ w≤ 100。
/* 打的暴力,30分。 其实正解似乎很好理解,但是没想到。 因为当一张图只包含1-n的最短路径时,它一定是棵树,所以我们只要知道某个点它有多少边在最短路径中,然后用乘法原理乘起来。 */ #include<cstdio> #include<iostream> #include<queue> #include<cstring> #define N 1010 #define lon long long using namespace std; int head[N],vis[N],dis[N],n,m;lon c[N]; struct node{ int v,pre,t; };node e[N*N*2]; void add(int i,int x,int y,int z){ e[i].v=y; e[i].t=z; e[i].pre=head[x]; head[x]=i; } void spfa(int s){ memset(dis,127/3,sizeof(dis)); queue<int> q;q.push(s); vis[s]=1;dis[s]=0; while(!q.empty()){ int u=q.front();vis[u]=0;q.pop(); for(int i=head[u];i;i=e[i].pre){ if(dis[e[i].v]>dis[u]+e[i].t){ dis[e[i].v]=dis[u]+e[i].t; if(!vis[e[i].v]){ vis[e[i].v]=1; q.push(e[i].v); } } } } } int main(){ freopen("castle.in","r",stdin); freopen("castle.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++){ int x,y,z;scanf("%d%d%d",&x,&y,&z); add(i*2-1,x,y,z);add(i*2,y,x,z); } spfa(1); queue<int> q;q.push(1);vis[1]=1;c[1]=1LL; while(!q.empty()){ int u=q.front();q.pop(); for(int i=head[u];i;i=e[i].pre){ if(dis[e[i].v]==dis[u]+e[i].t){ c[e[i].v]++; c[e[i].v]%=(lon)((1LL<<31LL)-1); if(!vis[e[i].v]){ q.push(e[i].v); vis[e[i].v]=1; } } } } lon ans=1; for(int i=1;i<=n;i++) ans*=c[i],ans%=(lon)((1LL<<31LL)-1); cout<<ans; return 0; }