一本通 黑暗城堡

描述
你知道黑暗城堡有 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;
}
posted @ 2020-12-06 15:49  索饮  阅读(90)  评论(0编辑  收藏  举报