1. 程式人生 > 實用技巧 >一本通 黑暗城堡

一本通 黑暗城堡

描述
你知道黑暗城堡有 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;
}