最短路径树问题:
这题必须满足,dis[1][j]==d[j] (dis[1][j]表示1-j的距离,d[j]表示最终生成的树1-j的距离)
思路:我们按dis[1][j]从小到大的顺序一个一个点的放进最终树的集合S中:
每次插入的点x,只要在集合中的点j满足 a[x][j]+dis[1][j]==dis[1][x],这条边就是可以连接的。
每次插入点都会优若干个边可以连接。根据乘法原理,依次相乘就是最终方案数(排列不会影响最终方案,点数加入顺序不影响方案,影响方案的只是边连接的方法!!)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 1e6+7;
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y,int w){ee[++cnt].nxt=head[x],ee[cnt].val=w,ee[cnt].to=y,head[x]=cnt;}
ll mod=2147483647;
int vs[M];
int d[M];
int a[1010][1010];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m,u,v,w;
cin>>n>>m;
memset(a,0x3f,sizeof(a));
for(int i=1;i<=m;i++)cin>>u>>v>>w,add(u,v,w),add(v,u,w),a[u][v]=a[v][u]=w;
ll ans=1;
memset(d,0x3f,sizeof(d));
d[1]=0;
for(int i=1;i<=n;i++)//加点的顺序不影响最终方案,所以按到1号点的距离加点顺序即可。
{
int x=0;//第i次操作把x点加入到MST集合中
for(int j=1;j<=n;j++)
if(!vs[j]&&(x==0||d[j]<d[x]))x=j;
vs[x]=1;
int tp=0;
for(int j=1;j<=n;j++)
if(!vs[j])d[j]=min(d[j],a[x][j]+d[x]);
else if(d[x]==d[j]+a[x][j])tp++;//p点可以与MST点集新形成的边数
//cout<<x<<" "<<d[x]<<"==="<<tp<<endl;
if(tp)ans=ans*tp%mod;//乘法原理
}
cout<<ans<<endl;
return 0;
}