描述
在顺利攻破Lord lsp的防线之后,lqr一行人来到了Lord lsp的城堡下方。Lord lsp黑化之后虽然拥有了强大的超能力,能够用意念力制造建筑物,但是智商水平却没怎么增加。现在lqr已经搞清楚黑暗城堡有N个房间 (1≤N≤1000),M条可以制造的双向通道,以及每条通道的长度。
lqr深知Lord lsp的想法,为了避免每次都要琢磨两个房间之间的最短路径,Lord lsp一定会把城堡修建成树形的;但是,为了尽量提高自己的移动效率,Lord lsp一定会使得城堡满足下面的条件:设 D[i] 为如果所有的通道都被修建,第 i 号房间与第1号房间的最短路径长度;而 S[i] 为实际修建的树形城堡中第 i 号房间与第1号房间的路径长度;要求对于所有整数 i(1≤i≤N),有 S[i]=D[i] 成立。
为了打败Lord lsp,lqr想知道有多少种不同的城堡修建方案。于是lqr向applepi提出了这个问题。因为applepi还要忙着出模拟赛,所以这个任务就交给你了。当然,你只需要输出答案对 2^31–1 取模之后的结果就行了。
输入
第一行有两个整数N 和M。
之后M 行,每行三个整数X,Y 和L,表示可以修建X 和Y 之间的一条长度为L 的通道。
输出
一个整数,表示答案对 2^31–1 取模之后的结果。
样例输入
3 3
1 2 2
1 3 1
2 3 1
样例输出
2
解题思路:dij找出在最短路径上的边。统计出能构成最短路径树时每个点经过几次,相乘就是答案。
#include <bits/stdc++.h>
#define pii pair<int,int>
#define LL __int64
#define INF 0x3f3f3f3f
using namespace std;
const int N=1e3+5;
vector<pii>G[N];
int M[N][N];
int n,m;
const LL mod=pow(2,31)-1;
struct node
{
int id;
LL d;
}dis[N];
void dij()
{
for(int i=1;i<=n;i++) dis[i].d=INF,dis[i].id=i;
dis[1].d=0;
queue<int>qu;
qu.push(1);
while(!qu.empty()){
int u=qu.front();qu.pop();
for(int i=0;i<G[u].size();i++){
int v=G[u][i].first,c=G[u][i].second;
if(dis[v].d>dis[u].d+c){
dis[v].d=dis[u].d+c;
qu.push(v);
}
}
}
}
bool cmp(node a,node b)
{
if(a.d!=b.d) return a.d<b.d;
return a.id<b.id;
}
int main()
{
int k;
ios::sync_with_stdio(false);
cin>>n>>m;
memset(M,INF,sizeof(M));
for(int i=1,u,v,c;i<=m;i++){
cin>>u>>v>>c;
M[u][v]=M[v][u]=min(M[u][v],c);
G[u].push_back(pii(v,c));
G[v].push_back(pii(u,c));
}
dij();
LL sum=1;
sort(dis+1,dis+1+n,cmp);
for(int i=2;i<=n;i++){
LL cnt=0;
for(int j=1;j<i;j++){
int u=dis[j].id,v=dis[i].id;
//cout<<u<<" "<<v<<endl;
if(dis[j].d+M[u][v]==dis[i].d) cnt++;
}
sum=sum*cnt%mod;
}
cout<<sum<<endl;
}