1. 程式人生 > >hdu 2376(求樹上任意兩點之間距離之和的平均值)

hdu 2376(求樹上任意兩點之間距離之和的平均值)

思路:

引:如果暴力列舉兩點再求距離是顯然會超時的。轉換一下思路,我們可以對每條邊,求所有可能的路徑經過此邊的次數:設這條邊兩端的點數分別為A和B,那 麼這條邊被經過的次數就是A*B,它對總的距離和的貢獻就是(A*B*此邊長度)。我們把所有邊的貢獻求總和,再除以總路徑數N*(N-1)/2,即為最 後所求。

每條邊兩端的點數的計算,實際上是可以用一次dfs解決的。任取一點為根,在dfs的過程中,對每個點k記錄其子樹包含的點數(包括其自身),設點數為a[k],則k的父親一側的點數即為N-a[k]。這個統計可以和遍歷同時進行。故時間複雜度為O(n)。

 1 #include<iostream>
 2
#include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<vector> 7 using namespace std; 8 #define MAXN 10000+10 9 struct Node{ 10 int v,len; 11 }; 12 vector<Node>vet[MAXN]; 13 int n; 14 double dp[MAXN]; 15 int sum[MAXN]; 16 17 void
dfs(int root,int father){ 18 sum[root]=1; 19 for(int i=0;i<vet[root].size();i++){ 20 int son=vet[root][i].v; 21 int len=vet[root][i].len; 22 if(son==father)continue; 23 dfs(son,root); 24 sum[root]+=sum[son]; 25 dp[root]+=dp[son]+(sum[son]*(n-sum[son]))*(double
)len; 26 } 27 } 28 29 int main(){ 30 // freopen("1.txt","r",stdin); 31 int _case,u,v,len; 32 scanf("%d",&_case); 33 while(_case--){ 34 scanf("%d",&n); 35 for(int i=0;i<=n;i++)vet[i].clear(); 36 for(int i=1;i<=n-1;i++){ 37 scanf("%d%d%d",&u,&v,&len); 38 Node p1,p2; 39 p1.v=v,p2.v=u; 40 p1.len=p2.len=len; 41 vet[u].push_back(p1); 42 vet[v].push_back(p2); 43 } 44 memset(sum,0,sizeof(sum)); 45 memset(dp,0,sizeof(dp)); 46 dfs(0,-1); 47 int s=(n*(n-1)/2); 48 printf("%1lf\n",(double)dp[0]/s); 49 } 50 return 0; 51 }
View Code