题目链接:黑暗城堡
思路:首先用SPFA算法求出每个点到1号点的最短距离。如果一个节点到1号节点的最短路 = 另一个和它有连边的节点到根节点的最短路 + 它们两个节点之间的直接距离,那么答案数就加一
#include<stdio.h>
#include<string.h>
#include<queue>
#include<math.h>
#include<stack>
#include<algorithm>
using namespace std;
const long long mod=pow(2,31)-1;
int inf=0x3f3f3f3f;
const int maxn=1e6+50;
long long e[1001][1001];
int n,m,num=0;
int dis[maxn];//用来记录源点到其余各个顶点的最短路径
int first[maxn],next1[maxn],book[maxn];
int v[maxn],w[maxn],u[maxn];//表示从顶点u[i]到顶点v[i]这条边的权重w[i]
struct s
{
int u,v;
long long w;
}s1[58862458];
void add(int a,int b,int c)//链式向前星
{
v[num]=b;
w[num]=c;
next1[num]=first[a];
first[a]=num++;
}
void spfa(int x)//spfa算法模板
{
int i;
stack<int>q;
memset(dis,inf,sizeof(dis));
memset(book,0,sizeof(book));
dis[x]=0;
book[x]=1;//book表示此点是否已是最短路
q.push(x);
while(!q.empty())
{
int u=q.top();
q.pop();
book[u]=0;
for(i=first[u];i!=-1;i=next1[i])
{
if(dis[v[i]]>dis[u]+w[i])
{
dis[v[i]]=dis[u]+w[i];
if(book[v[i]]==0)
{
book[v[i]]=1;
q.push(v[i]);
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
//初始化
memset(e,inf,sizeof(e));
memset(first,-1,sizeof(first));
memset(next1,-1,sizeof(next1));
for(int i=0;i<m;i++)
{
//printf("****\n");
scanf("%d%d%lld",&s1[i].u,&s1[i].v,&s1[i].w);//因为是无向图
add(s1[i].u,s1[i].v,s1[i].w);
add(s1[i].v,s1[i].u,s1[i].w);
e[s1[i].u][s1[i].v]=e[s1[i].v][s1[i].u]=min(e[s1[i].u][s1[i].v],s1[i].w);
//避免出现错误
}
spfa(1);
long long p=1;
//dis数组表示为各点到1的最短距离
for(int i=2;i<=n;i++)//1号店除外
{
int sum=0;//sum为当前节点的方案数
//printf("%d\n",dis[i]);
for(int j=1;j<=n;j++)//枚举
{
//如果一个节点到1号节点的最短路 = 另一个和它有连边的节点到根节点的最短路 + 它们两个节点之间的直接距离,那么答案数++
if(dis[i]==dis[j]+e[i][j])
sum++;
}
if(sum)
p=p*sum%mod;//边乘边取模
}
printf("%lld\n",p);
}