51Nod 1405 樹的距離之和(dp)
阿新 • • 發佈:2019-02-10
基準時間限制:1 秒 空間限制:131072 KB 分值: 40 難度:4級演算法題
收藏
關注
給定一棵無根樹,假設它有n個節點,節點編號從1到n, 求任意兩點之間的距離(最短路徑)之和。
Input
第一行包含一個正整數n (n <= 100000),表示節點個數。 後面(n - 1)行,每行兩個整數表示樹的邊。Output
每行一個整數,第i(i = 1,2,...n)行表示所有節點到第i個點的距離之和。Input示例
4 1 2 3 2 4 2Output示例
5 3 5 5
思路:
首先,任選一個節點,設定為樹的根。
用num[x]表示以節點x為根的子樹的節點總數(包含x自身)
假如設定節點1為根,則先求出dp[1],表示所有節點到節點1的距離之和,
對根而言也是所有節點的深度之和。
若x是y的子結點,則有
dp[x] = dp[y] + (n-num[x]) - num[x];
因為x為根的子樹的所有節點到x的距離比到y的距離少1,所以減num[x]
其餘節點到x的距離比到y的距離多1,所以加 n-num[x]
程式碼:
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <cstdlib> #include <vector> #pragma comment(linker, "/STACK:10240000,10240000")//遞迴太深,導致爆棧,所以使用擴棧語句 using namespace std; const int N = 100009; int dp[N] = {}, num[N]; vector<int> p[N]; bool f[N] = {}; void dfs(int s, int depth) { int len = p[s].size(); f[s] = 1; num[s] = 1; dp[1] += depth; for(int i=0; i<len; i++) { if(!f[p[s][i]]) { dfs(p[s][i], depth+1); num[s] += num[p[s][i]]; } } } void solve(int s, int n) { int len = p[s].size(); f[s] = 1; for(int 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], n); } } } int main() { int n; scanf("%d", &n); for(int i=1; i<n; i++) { int a, b; scanf("%d%d", &a, &b); p[a].push_back(b); p[b].push_back(a); } dfs(1, 0); memset(f, 0, sizeof(f)); solve(1, n); for(int i=1; i<=n; i++) printf("%d\n", dp[i]); return 0; }