1. 程式人生 > >51nod 1405 樹的距離之和 搜尋+DP

51nod 1405 樹的距離之和 搜尋+DP

Input
第一行包含一個正整數n (n <= 100000),表示節點個數。
後面(n - 1)行,每行兩個整數表示樹的邊。
Output
每行一個整數,第i(i = 1,2,...n)行表示所有節點到第i個點的距離之和。
Input示例
4
1 2
3 2
4 2
Output示例
5
3
5

5

假設以第一個點為根節點,我們開始搜尋,記錄以當前節點的深度以及當前節點的子節點個數。

之後對於統計。

對於X節點,我們已經知道他的距離之和為dp【X】了。

那麼他的子節點Y節點。

dp【Y】=dp[X] - num[y] + n - num[y]

解釋一下:其他點到達y,有兩種情況。第一種點在y節點的子樹上。 也就是num【y】個,這num【y】個點

到達y要比到達x小1. 所以dp【x】-num【y】. 第二種情況,不在y的子樹上的點,也就是n-num【y】個,

他們要比到達x多1.所以在原來的基礎上再加上n - num[y]。

那麼我們dfs來求dp即可。

#include<stdio.h> #include<string.h> #include<algorithm> #include<vector> #include<iostream> using namespace std; vector<long long>p[100010]; bool f[100010];//是否訪問過 long long dp[100010];//當前深度到S的深度 long long num[100010];//子節點數量 long long n; void dfs(long long s,long long depth) {     long long len=p[s].size();     f[s]=1;     num[s]=1;     dp[1]+=depth;     for(long long i=0;i<len;i++)     {         if(!f[p[s][i]])         {             dfs(p[s][i],depth+1);             num[s]+=num[p[s][i]];         }     } } void solve(long long s) {     long long len=p[s].size();     f[s]=1;     for(long long i=0;i<len;i++)     {         if(!f[p[s][i]])         {             dp[p[s][i]]=dp[s]+n-num[p[s][i]]*2;             solve(p[s][i]);         }     } } int main() {     cin>>n;     for(long long i=2;i<=n;i++)     {         long long a,b;         cin>>a>>b;         p[a].push_back(b);         p[b].push_back(a);     }     dfs(1,0);     memset(f,0,sizeof(f));     solve(1);     for(long long i=1;i<=n;i++)         cout<<dp[i]<<endl; }