一本通 黑暗城堡
描述
你知道黑暗城堡有 NN个房间,MM 条可以制造的双向通道,以及每条通道的长度。
城堡是树形的并且满足下面的条件:
设 DiDi为如果所有的通道都被修建,第 ii 号房间与第 11 号房间的最短路径长度;
而SiSi 为实际修建的树形城堡中第 ii 号房间与第 11 号房间的路径长度;
要求对于所有整数 ii (1≤i≤N1≤i≤N),有 Si=DiSi=Di 成立。
你想知道有多少种不同的城堡修建方案。当然,你只需要输出答案对 231−1231−1 取模之后的结果就行了。
输入
第一行为两个由空格隔开的整数 N,MN,M;
第二行到第 M+1M+1 行为 33个由空格隔开的整数x,y,lx,y,l:表示 xx 号房间与 yy 号房间之间的通道长度为ll。
输出
一个整数:不同的城堡修建方案数对 231−1231−1 取模之后的结果。
样例输入
4 6
1 2 1
1 3 2
1 4 3
2 3 1
2 4 2
3 4 1
样例输出
6
思路:普普通通的dijk可能有重边所以记得取最小的。对所有的边求完最短路后,可能会存在某两个点之间存在好几个长度一样的最短路;
最后看一下两个点之间可以有几条一样最短路,计数就可。
if (dis[i]==dis[j]+e[j][i])
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e4+10,inf=0x3f3f3f;
ll mod=pow(2,31)-1;
int dis[maxn],book[maxn],e[maxn][maxn],n,m;
void dijk()
{
int minn,k,i,j,u;
memset(dis,0,sizeof(dis));
memset(book,0,sizeof(book));
for (i=1; i<=n; i++)
dis[i]=e[1][i];//
book[1]=1;
for (i=1; i<n; i++)
{
minn=inf;
for (j=1; j<=n; j++)
{
if (!book[j]&&dis[j]<minn)
{
minn=dis[j];
u=j;
}
}
book[u]=1;
for (j=1; j<=n; j++)
{
if (!book[j])
dis[j]=min(dis[u]+e[u][j],dis[j]);
}
}
}
int main()
{
int i,j;
scanf("%d%d",&n,&m);
for (i=1; i<=n; i++)
for (j=1; j<=n; j++)
if (i==j)
e[i][j]=0;
else
e[i][j]=inf;
while(m--)
{
int x,y,l;
scanf("%d %d %d",&x,&y,&l);
e[x][y]=e[y][x]=min(e[x][y],l);
}
dijk();
ll ans=1;
int cnt;
for (i=2; i<=n; i++)
{
cnt=0;
for (j=1; j<=n; j++)
{
if (e[i][j])
{
if (dis[i]==dis[j]+e[j][i])
cnt++;//
}
}
ans=(ans*cnt)%mod;
}
printf("%lld\n",ans);
return 0;
}