L - Computer(HDU2196 ,树形DP,换根法)

本文详细介绍了L-Computer问题(HDU2196)的解决策略,通过树形动态规划(树形DP)与换根法实现。首先将无根树转化为有根树,进行两遍深度优先搜索(DFS),计算每个节点的最大和次大距离,最终得到每个节点作为根时的最大距离。

L - Computer(HDU2196 ,树形DP,换根法)

题目 :传送门

思路见注释

代码 :
*
换根法dp:
先把无根树化为有根树
第一遍dfs,对于顶点u,求u的子树到u的最大和次大距离
第二遍dfs,将树化为顶点u为根,求u的子树到u的最大距离和次大距离
    对于u的最大距离就是u的答案res[u],而u的次大距离是用来儿子换根的时候进行状态转移
*/
#include<bits/stdc++.h>
#define mset(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int inf=0x3f3f3f3f;
const ll N=1e4+10;
const ll mod=1e9+7;
vector<P> g[N];
int dp[N][2];//u的最大值与次大值
int pos[N][2];//u的最大值与次大值的位置
int res[N];
void dfs1(int u,int fa)
{
    for(P &p:g[u])
    {
        int v=p.first,w=p.second;
        if(v==fa) continue;
        dfs1(v,u);
        if(dp[v][0]+w>dp[u][0]){
            dp[u][1]=dp[u][0];
            pos[u][1]=pos[u][0];
            dp[u][0]=dp[v][0]+w;
            pos[u][0]=v;
        }
        else if(dp[v][0]+w>dp[u][1]){
            dp[u][1]=dp[v][0]+w;
            pos[u][1]=v;
        }
    }
//    printf("u:%d,dp[0]:%d,pos[0]:%d,dp[1]:%d,pos[1]:%d\n",u,dp[u][0],pos[u][0],dp[u][1],pos[u][1]);
}
void dfs2(int u,int fa,int w)
{
    int other=0;
    if(fa!=u)//再次换根为u,更新最大和次大
    {
         if(pos[fa][0]!=u)//other代表从父亲到该根的最大与次大
            other=dp[fa][0]+w;
         else
            other=dp[fa][1]+w;
         if(other>dp[u][0]){
            pos[u][1]=pos[u][0];
            dp[u][1]=dp[u][0];
            pos[u][0]=fa;
            dp[u][0]=other;
         }
         else if(other>dp[u][1])
         {
             pos[u][1]=fa;
             dp[u][1]=other;
         }
    }
    res[u]=dp[u][0];
    for(P &p:g[u])
    {
        int v=p.first;
        if(v==fa) continue;
        dfs2(v,u,p.second);
    }
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    int n;
    while(cin>>n)
    {
        for(int i=1;i<=n;++i) g[i].clear();
        for(int i=2;i<=n;++i){
            int w,v;
            cin>>v>>w;
            g[i].push_back({v,w});
            g[v].push_back({i,w});
        }
        mset(dp,0);
        mset(pos,0);mset(res,0);
        dfs1(1,1);
        dfs2(1,1,0);
        for(int i=1;i<=n;++i){
            cout<<res[i]<<endl;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值