您的位置:首页 > 其它

51nod 1405 树的距离之和【树型dp】

2016-12-05 12:53 309 查看
1405 树的距离之和

基准时间限制: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 2


Output示例
5
3
5
5


思路:

(好难啊)思路源自:http://blog.csdn.net/to_be_better/article/details/50620434

1、虽然是一个无根树,但是我们可以设定节点1;

2、首先第一遍Dfs出一个数组num【i】,对应表示以第i个节点为根的子树内一共包含多少个节点(当然包括i这个节点);

同时我们可以在第一次Dfs的过程中,维护一个dp【1】,其表示其他所有节点到节点1的距离。

3、那么接下来我们再从节点1一次Dfs,同时维护dp状态转移方程:dp【v】=dp【u】-num【v】+(n-num【v】);

其中所有节点到u的距离作为基础,

①因为此时点向子树挪动距离为1,那么其v的子树中的所有节点到v的距离比到u的距离小1,那么对应减去。

②因为此时点向子树挪动距离为1,那么其u的上边的树上的所有节点到v的距离比到u的距离大1,那么对应加上。

4、注意会爆int。

Ac代码:

#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
#define ll __int64
int num[105000];
int vis[105000];
ll dp[105000];
vector<int >mp[105000];
int n;
int Dfs(int u,int sum)
{
dp[1]+=sum;
num[u]=1;
vis[u]=1;
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
if(vis[v]==0)
{
Dfs(v,sum+1);
num[u]+=num[v];
}
}
}
void Dfs_dp(int u)
{
vis[u]=1;
for(int i=0;i<mp[u].size();i++)
{
int v=mp[u][i];
if(vis[v]==0)
{
dp[v]=dp[u]-num[v]+(n-num[v]);
Dfs_dp(v);
}
}
}
int main()
{
while(~scanf("%d",&n))
{
memset(num,0,sizeof(num));
memset(dp,0,sizeof(dp));
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
mp[x].push_back(y);
mp[y].push_back(x);
}
memset(vis,0,sizeof(vis));
Dfs(1,0);
memset(vis,0,sizeof(vis));
Dfs_dp(1);
for(int i=1;i<=n;i++)
{
printf("%I64d\n",dp[i]);
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  51nod 1405