描述
在顺利攻破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; }