20251201换根DP总结

引子

说白了就是两次 DFS,第一次 DFS 预处理深度,点权和之类的信息,第二次 DFS 开始运行换根动态规划,题目比较简单的都很板。

P3478 POI 2008 STA-Station

换根DP模板。

"换根"过程参考图。

原图
1
2
3
4
5
6

假设现在dfs到了1,枚举儿子时找到了2,那么预处理得知dp[1]=11,换根之后示意图。
2
1
3
4
5
6

改变了什么?显然目前根结点在原图上的向上子树距离目前根节点的距离+1,其余结点距离目前根节点的距离-1,那么动态转移方程为dp[v]=dp[x]-sz[v]+(n-sz[v]),也可以写成dp[v]=dp[x]-sz[v]*2+n

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
vector<int> E[1000005];
long long n,dp[1000005],dep[1000005],sz[1000005];
//    结点数 DP数组        深度        子树结点数
void dfs(int x,int fa){
    dp[1]+=dep[x];//先求出根节点为1的答案
    sz[x]=1;//自己算一个
    for(int i=0;i<E[x].size();i++){
        int v=E[x][i];
        if(v==fa)continue;
        dep[v]=dep[x]+1;//直接求
        dfs(v,x);
        sz[x]+=sz[v];//加上儿子的
    }
}
void dfs1(int x,int fa){
    for(int i=0;i<E[x].size();i++){
        int v=E[x][i];//儿子节点
        if(v==fa)continue;
        dp[v]=dp[x]-sz[v]+(n-sz[v]);//核心代码,其余全是预处理
        //计算儿子结点的DP
        dfs1(v,x);
    }
}
int main(){
    cin>>n;
    for(int i=1;i<n;i++){
        int u,v;
        cin>>u>>v;
        E[u].push_back(v);
        E[v].push_back(u);
    }
    dfs(1,0);
    dfs1(1,0);
    long long mn=0,m;//看题
    for(int i=1;i<=n;i++){
        if(dp[i]>mn){
            mn=dp[i];
            m=i;
        }
    }
    cout<<m;
    return 0;
}
相关推荐
All for pursuit.14 分钟前
【链表-9】146.LRU缓存
数据结构·c++·算法·leetcode
木子算法14 分钟前
测出来的值会抖:约束和目标带噪声时,「可行」和「更好」该怎么判
人工智能·算法·目标跟踪
hanlin031 小时前
刷题笔记:力扣第144题-二叉树的前序遍历
笔记·算法·leetcode
金士曼1 小时前
从规则到涌现:算法认知的三个层次
算法
AgentMaster2 小时前
数据资产化落地难题:5款数据中台系统架构对比与实施记录
大数据·人工智能·算法
Logic1013 小时前
C语言/数据结构动态规划题解:Kadane算法求最大子数组和——O(n)时间O(1)空间
c语言·数据结构·动态规划·贪心·时间复杂度·算法题·最大子数组和
鹿角片ljp3 小时前
从 Kimi Cyber Reasoning 学习网络安全推理数据集:从 Reasoning SFT 到安全 Agent 数据设计
数据结构·算法
residual_fan4 小时前
航空发动机故障诊断专用智能体(三):基于对比学习的时序特征区分方法
人工智能·算法·数据挖掘·数据分析
高亦真4 小时前
今天是学习嵌入式的第39天
linux·学习·算法
Omics Pro4 小时前
AI药物研发10原则!欧盟EMA×美国FDA
数据库·人工智能·算法·机器学习·自然语言处理