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

基准时间限制: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]);
        }
    }
}







  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值