题目描述
你知道黑暗城堡有 N 个房间,M 条可以制造的双向通道,以及每条通道的长度。
城堡是树形的并且满足下面的条件:
设 Di 为如果所有的通道都被修建,第 i 号房间与第 1 号房间的最短路径长度;
而 Si 为实际修建的树形城堡中第 i 号房间与第 1 号房间的路径长度;
要求对于所有整数 i (1≤i≤N),有 Si=Di 成立。
你想知道有多少种不同的城堡修建方案。当然,你只需要输出答案对 2^31 取模之后的结果就行了。
输入格式
第一行为两个由空格隔开的整数 N,M;
第二行到第 M+1 行为 3 个由空格隔开的整数 x,y,l:表示 x 号房间与 y 号房间之间的通道长度为 l。
输出格式
一个整数:不同的城堡修建方案数对 2^31 取模之后的结果。
样例
样例输入
4 6
1 2 1
1 3 2
1 4 3
2 3 1
2 4 2
3 4 1
样例输出
6
样例说明
一共有 4 个房间,6 条道路,其中 1 号和 2 号,1 号和 3 号,1 号和 4 号,2 号和 3 号,2 号和 4 号,3 号和 4 号房间之间的通道长度分别为 1,2,3,1,2,1。
而不同的城堡修建方案数对 2^31 取模之后的结果为 6。
数据范围与提示
对于全部数据,1≤N≤1000,1≤M≤N(N−1)/2,1≤l≤200。
题意:
求一个无向图中最短路径树的棵数。
最短路径树的定义:
选出$N-1$条边组成一棵树,对于给定的源点$S$,
若任何点$u$均满足在原图上$S$到点$u$的最短路$dis(u)$等于在这棵树上$S$到$u$的最短路$disnew(u)$,
则这棵树是一棵最短路径树。
我的直观感受:答案应该等于$S$到每个点的最短路条数的乘积吧?
然后写了。错了。发现输入写错了。
(千万不要把连边读入写成$add(read(),read(),read())$,这玩意好像是反着读进来的)
改了输入,$A$了。
……
考虑生成一棵最短路径树的方法,只需要在$dis(v)>dis(u)+e(u,v)$(即发生更新)时记录$fa(v)=u$,
最后按父子关系把树连起来即可。由于每个点都有且仅有一个$fa$,可以证明这一定是一棵树。
我们发现,若出现一个$v$使得$dis(v)=dis(u)+e(u,v)$,$fa(v)$便有两种选择,任取一种均合法。
推广开来,当出现$N$个$dis(v)=dis(u)+e(u,v)$时,$fa(v)$便有$N+1$种选择,任取一种均合法。
(由于$dis(v)=dis(u)+e(u,v)$这样的状态不会影响最短路算法的运行,所以$fa(v)$取何值都不会对其他点产生影响)
既然每个点互不影响,我们就可以直接运用乘法原理把每个$v$的选择数乘起来得到答案。
显然$v$的选择数就是$S\rightarrow v$的最短路的条数,打板即可。
代码:
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; #define MAXN 100005 #define MAXM 1000005 #define mod 0x7fffffff #define ll long long ll hd[MAXN],to[MAXM<<1],cnt; ll nxt[MAXM<<1],cst[MAXM<<1]; struct node{ ll u,w; bool operator<(const node b)const {return w>b.w;} }; ll dis[MAXN],ans[MAXN]; bool vis[MAXN]; inline ll read(){ ll x=0,f=1; char c=getchar(); for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; } inline void addedge(ll u,ll v,ll w){ to[++cnt]=v,cst[cnt]=w,nxt[cnt]=hd[u],hd[u]=cnt; to[++cnt]=u,cst[cnt]=w,nxt[cnt]=hd[v],hd[v]=cnt; return; } inline void Dijkstra(ll s){ memset(dis,127,sizeof(dis)); priority_queue<node> q; q.push((node){s,0}); ans[1]=1;dis[s]=0; while(!q.empty()){ node tp=q.top();q.pop(); if(vis[tp.u]) continue; vis[tp.u]=1; for(ll i=hd[tp.u];i;i=nxt[i]){ ll v=to[i],w=cst[i]; if(dis[v]>tp.w+w){ ans[v]=1,dis[v]=tp.w+w; q.push((node){v,dis[v]}); } else if(dis[v]==tp.w+w) ans[v]++; } } return; } int main(){ ll N=read(),M=read(),num=1; for(ll i=1;i<=M;i++){ ll u=read(),v=read(),w=read(); addedge(u,v,w); } Dijkstra(1); for(ll i=1;i<=N;i++) num*=ans[i]%mod,num%=mod; printf("%lld\n",num%mod); return 0; }