描述
给定一棵包含N个节点的树,节点编号1~N。
请你对于每一个节点,计算它到所有其他节点的距离之和。(每条边的长度为1)
输入
第一行包含一个整数N。
以下N-1行,每行包含两个整数a和b,代表ab之间有一条边。
对于30%的数据,1 ≤ N ≤ 1000
对于100%的数据,1 ≤ N ≤ 100000
输出
输出N行,依次对于1~N号节点输出答案。
4 1 2 2 3 2 4样例输出
5 3 5 5
题意不用说了,直接说思路。先选定节点1作为树的根,然后用num[i]表示以节点i为根的子树上的节点数(包括i)。
dp[x]表示节点x到其他所有节点距离之和,设节点x是节点xx的父节点。
那么我们可以得到dp[xx] = dp[x] + (n-num[xx]) - num[xx]。
因为在xx子树上的节点到xx的距离要比到父节点x的距离要少1,所以减去1,一共有num[xx]个,所以减去num[xx]
不在xx子树上的节点到xx的距离要比到父节点x的距离要多1,所以加上n - num[xx]。
这样我们首先一个dfs处理出dp[1]的大小,就可以推出其他的大小。
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int N = 1000010;
int n;
LL dp[N];
int vis[N];
int num[N];
vector<int> e[N];
void dfs(int x,int s)
{
vis[x] = 1;
num[x] = 1;
dp[1] += s;
for(int i=0;i<e[x].size();i++)
{
int xx = e[x][i];
if(vis[xx] == 0)
{
dfs(xx,s+1);
num[x] += num[xx];
}
}
}
void init_dp(int x)
{
vis[x] = 1;
for(int i=0;i<e[x].size();i++)
{
int xx = e[x][i];
if(vis[xx] == 0)
{
dp[xx] = dp[x] + (n-num[xx]) - num[xx];
init_dp(xx);
}
}
}
int main(void)
{
int i,j;
while(scanf("%d",&n)==1)
{
for(i=1;i<=n;i++)
e[i].clear();
for(i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
e[x].push_back(y);
e[y].push_back(x);
}
dp[1] = 0;
memset(vis,0,sizeof(vis));
dfs(1,0);
memset(vis,0,sizeof(vis));
init_dp(1);
for(i=1;i<=n;i++)
printf("%d\n",dp[i]);
}
return 0;
}
本文介绍了一种使用树形DP算法解决特定问题的方法:计算树中每个节点到其它所有节点距离之和。通过选定根节点并递归地计算子树节点数量和距离之和,最终得出所有节点的答案。
4453

被折叠的 条评论
为什么被折叠?



