一本通1486:【例題1】黑暗城堡

評測地點

【題目描述】

知道黑暗城堡有 N 個房間, M 條能夠製造的雙向通道,以及每條通道的長度。php

城堡是樹形的而且知足下面的條件:ios

設$ D_i$爲若是全部的通道都被修建,第 i 號房間與第 1 號房間的最短路徑長度;git

\(S_i\) 爲實際修建的樹形城堡中第$ i$ 號房間與第$ 1 $號房間的路徑長度;算法

要求對於全部整數 \(i(1≤i≤N)\),有$ S_i=D_i$ 成立。數組

你想知道有多少種不一樣的城堡修建方案。固然,你只須要輸出答案對 \(2^{31}−1\) 取模以後的結果就好了。spa

【輸入】

第一行爲兩個由空格隔開的整數 \(N,M\);
第二行到第 \(M+1\) 行爲 \(3\) 個由空格隔開的整數$ x,y,l$:表示 \(x\) 號房間與$ y$ 號房間之間的通道長度爲 \(l\)code

【輸出】

一個整數:不一樣的城堡修建方案數對\(2^{31}-1\) 取模以後的結果。ip

【輸入樣例】

4 6
1 2 1
1 3 2
1 4 3
2 3 1
2 4 2
3 4 1

【輸出樣例】

6

【提示】

樣例說明get

一共有$ 4$ 個房間,\(6\) 條道路,其中 1 號和$ 2$ 號,$ 1 $號和 3 號,\(1\) 號和 \(4\) 號,\(2\) 號和$ 3$ 號,\(2\) 號和 $4 $號,\(3\) 號和 \(4\) 號房間之間的通道長度分別爲$ 1,2,3,1,2,1。$string

而不一樣的城堡修建方案數對 $2^{31}−1 $取模以後的結果爲 \(6\)

數據範圍:

對於所有數據,\(1≤N≤1000,1≤M≤ \dfrac{N(N-1)}{2},1≤l≤200。\)

【分析】

先用\(dijkstra\)求出1號房間到每一個房間的單源最短路徑存儲到\(dis\)數組中。把樹形城堡看做以1爲根的有根樹。由題,若\(x\)\(y\)的根節點,\(x、y\)之間的通道長度爲\(z\),則應該有:\(dis[y]=dis[x]+z\)。事實上,咱們把知足題目要求的樹結構,即對任意一對父子結點\(x、y\)都有上式成立的樹結構,稱爲圖的一棵最短路徑生成樹。與\(Prim\)算法相似,統計有多少結點\(x\)知足\(dis[p]=dis[x]+e[x][p]\),讓\(p\)與其中任意一個x相連都符合題目要求。

【注意】

最短路徑生成樹:對於任意一對父子結點\(x、y\)均知足\(dis[y]=dis[x]+e[x][y]\)的樹結構稱爲圖的一棵最短路徑生成樹;
在宏定義中!! \(2^{31-1}\) 寫爲  \((1<<31)-1\)  要加括號!! 要加括號!! 否則就會\(wa\)好多好屢次了...
而後,不要忘了給\(e\)數組初始化....否則就默認爲0了..
這題數據範圍比較小,因此能夠用鄰接矩陣,不過這個是樹,稀疏圖,通常是用鄰接表的。

【代碼】

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<iomanip>
#include<cstdlib>
#include<queue>
#include<map>
#include<set>
#include<stack>
#include<vector>
#define ll long long
using namespace std;
inline ll read()
{
   ll s=0,w=1;
   char ch=getchar();
   while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
   while(isdigit(ch)) s=s*10+ch-'0',ch=getchar();
   return s*w;
}
int n,m;
ll dis[1010][1010],g[20000],cnt[20000];
bool vis[2000000]={0};
int main()
{
    n=read(),m=read();
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++)//1.預處理
        if(i==j)
            dis[i][j]=0;
        else
            dis[j][i]=dis[i][j]=1e18;
    for(int i=1,x,y,z;i<=m;i++)
    {
        x=read(),y=read(),z=read();
        if(dis[x][y]>z)
            dis[x][y]=dis[y][x]=z;//注意這一步判斷
    }
    for(int i=1;i<=n;i++)
        g[i]=dis[1][i];
    for(int i=1;i<=n;i++)//2.用dijkstra算法求出一號房間到每一個房間的最短路
    {
        ll minn=1e18,u;
        for(int j=1;j<=n;j++)
            if(!vis[j]&&minn>g[j])
                minn=g[j],u=j;
        vis[u]=1;
        for(int j=1;j<=n;j++)
            if(g[j]>dis[u][j]+g[u])
                g[j]=g[u]+dis[u][j];
    }
    ll ans=1;
    for(int i=1;i<=n;i++)//3.方案累加
        for(int j=1;j<=n;j++)
            if(i!=j&&g[j]==g[i]+dis[i][j])
            cnt[j]++;
    for(int i=1;i<=n;i++)
        if(cnt[i])
        ans*=cnt[i],ans%=2147483647;
    printf("%lld",ans);
    return 0;
}
相關文章
相關標籤/搜索