1. 程式人生 > >樹的計數

樹的計數

數據規模 long 而且 style cst span 代碼 想法 string

題目:

1.樹的計數

【問題描述】

圖和樹有很密切的關系。某一天牙神產生了一個很奇怪的想法:刪去一些邊把一個無向圖變成一個樹,也就是將邊留下 N ? 1 條。而且對於任意一個點 i,要保證現在樹中的邊滿足 1 號點到 i 號點的路徑長度等於原圖中 1 號點到 i 號點的最短路長度。牙神請你幫忙數一下有多少個目標樹滿足要求。答案對1000000007 取模。

【輸入格式】

第一行,一個整數N。接下來 N 行每行 N 個數,第 i 行第 j 個數表示 i 和 j 的連邊關系,0 表示沒有邊。

【輸出格式】

一個整數,表示答案。

【輸入樣例】

3

0 2 1

2 0 1

1 1 0

【輸出樣例】

2

【數據規模】

對於 40%數據 N ≤ 50

對於 100%數據 N ≤ 1000,每條邊邊權在[0,14]內。

題解:按照最短路徑的思想,記錄每一個點被假如已選集合的時候,有幾個點可以更新這個點的最短路徑。

按照乘法原理,最後答案就是每一個點的有幾個點可以更新這個點的最短路徑相乘

代碼:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=1005,M=1000000007;
int n,a[N][N],dis[N],g[N],f[N];
int main()
{
    freopen(
"treecnt.in","r",stdin); freopen("treecnt.out","w",stdout); scanf("%d",&n); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++)scanf("%d",&a[i][j]); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) if (!a[i][j])a[i][j]=10000005; for (int i=1;i<=n;i++)dis[i]=a[1
][i]; for (int i=1;i<=n;i++)g[i]=1; long long ans=1; f[1]=1; for (int i=1;i<n;i++) { int l=-1; for (int j=1;j<=n;j++) if (!f[j]&&(l==-1||dis[l]>dis[j]))l=j; f[l]=1; (ans*=g[l])%=M; for (int j=1;j<=n;j++) if (!f[j]) { if (dis[j]>dis[l]+a[l][j]) dis[j]=dis[l]+a[l][j],g[j]=0; if (dis[j]==dis[l]+a[l][j])g[j]++; } } printf("%lld",ans); }

樹的計數