Description
在顺利攻破 Lord lsp 的防线之后,lqr 一行人来到了 Lord lsp 的城堡下方。Lord lsp 黑化之后虽然拥有了强大的超能力,能够用意念力制造建筑物,但是智商水平却没怎么增加。现在 lqr 已经搞清楚黑暗城堡有 N 个房间,M 条可以制造的双向通道,以及每条通道的长度。lqr 深知 Lord lsp 的想法,为了避免每次都要琢磨两个房间之间的最短路径, Lord lsp一定会把城堡修建成树形的;但是,为了尽量提高自己的移动效率,Lord lsp 一定会使得城堡满足下面的条件:设 Di为如果所有的通道都被修建,第 i 号房间与第 1 号房间的最短路径长度;而 Si 为实际修建的树形城堡中第 i 号房间与第1 号房间的路径长度,对于所有满足 1≤i≤N 的整数 i,有 Si = Di。为了打败 Lord lsp,lqr想知道有多少种不同的城堡修建方案。于是 lqr 向 applepi 提出了这个问题。由于 applepi 还要忙着出模拟赛,所以这个任务就交给你了。当然,你只需要输出答案对 2^31 – 1 取模之后的结果就行了.
Input
第一行有两个整数 N 和 M。
之后 M 行,每行三个整数 X,Y 和 L,表示可以修建 X 和 Y 之间的一条长度为 L 的通道。
2≤N≤1000,N – 1≤M≤N(N – 1)/2,1≤L≤100
Output
输出一个整数,表示答案对 2^31 – 1 取模之后的结果。
Sample Input
3 3
1 2 2
1 3 1
2 3 1
Sample Output
2
首先求出单源最短路,然后考虑第i个点,我们可以枚举1~i-1个点,求出dis[j]+g[i][j]=dis[i]的点,然后使用乘法原理即可。由于第i个点不可能由那些dis比它大的点转移过来,因此我们要开始按dis排序
/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7fffffff
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
int x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*f;
}
inline void print(int x){
if (x>=10) print(x/10);
putchar(x%10+'0');
}
const int N=1e3,M=1e6,MOD=0x7fffffff;
struct S1{
#define ls (p<<1)
#define rs (p<<1|1)
#define fa (p>>1)
struct node{
int x,v;
bool operator <(const node &a)const{return v<a.v;}
}Q[N*50+10];
int tot;
void insert(int x,int v){
Q[++tot]=(node){x,v};
int p=tot;
while (p!=1&&Q[p]<Q[fa]) swap(Q[p],Q[fa]),p=fa;
}
void Delete(){
Q[1]=Q[tot--];
int p=1,son;
while (ls<=tot){
if (rs>tot||Q[ls]<Q[rs]) son=ls;
else son=rs;
if (Q[son]<Q[p]) swap(Q[p],Q[son]),p=son;
else break;
}
}
}Heap;
int pre[(M<<1)+10],now[N+10],child[(M<<1)+10],val[(M<<1)+10],tot;
int g[N+10][N+10],dis[N+10],ID[N+10];
bool vis[N+10];
void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}
bool cmp(const int &x,const int &y){return dis[x]<dis[y];}
void Dijkstra(int x){
memset(dis,63,sizeof(dis));
Heap.insert(x,dis[x]=0);
while (Heap.tot){
int Now=Heap.Q[1].x;
Heap.Delete();
if (vis[Now]) continue;
vis[Now]=1;
for (int p=now[Now],son=child[p];p;p=pre[p],son=child[p]){
if (dis[son]>dis[Now]+val[p]){
dis[son]=dis[Now]+val[p];
Heap.insert(son,dis[son]);
}
}
}
}
int main(){
int n=read(),m=read(),Ans=1;
memset(g,63,sizeof(g));
for (int i=1;i<=m;i++){
int x=read(),y=read(),z=read();
insert(x,y,z);
g[y][x]=g[x][y]=min(g[x][y],z);
}
for (int i=1;i<=n;i++) g[i][i]=0,ID[i]=i;
Dijkstra(1);
sort(ID+1,ID+1+n,cmp);
for (int i=2;i<=n;i++){
int res=0;
for (int j=1;j<i;j++)
if (dis[ID[j]]+g[ID[i]][ID[j]]==dis[ID[i]])
res++;
Ans=1ll*Ans*res%MOD;
}
printf("%d
",Ans);
return 0;
}