洛谷3629[APIO2010]巡逻(树的直径)DP+DFS

博客介绍了如何利用树形DP和DFS/BFS求解树的直径问题,详细解释了两种方法的思路和代码实现。文章特别提到,DP方法适用于边权为负数的情况,而搜索方法则不能处理负权,但能直接找出树的直径路径。此外,文章还讨论了在特定情况下的解决方案,如调整边权以适应不同情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

树的直径的一道很经典的题目

因为这个题巧妙的把两种求树的直径的做法都体现的淋漓尽致

  • 我先来介绍一下树的直径吧:
  • 在一棵树里,每一条边都有权值(树里面两个点之间的边权),那么树上最远的距离就为树的直径,当然我们大多数做的都是边权为1的树,这个时候也就是树上距离最远的两个点
  • 求解树的直径的两种方法
  • 1.树形DP
  • ans 来记录树的直径的长度,那么ans是怎么记录的呢?dist[i]表示从节点出发可以到达的最远的距离
  • 对于一个节点x,dist[x]是x节点可以到达的最远的距离(也就是最长链的距离),y是x的一个子节点,那么dist[x]是否小于 dist[y] + ver[x][y]呢
  • 那么答案是有可能的,那么这个时候dist[x]链就变成了次长链的距离,ans = 应该为当前节点的最长链长度+当前节点的次长链的长度。首先x的最长链的长度为dist[x],而经过从y的这个节点延申的链的长度+ver[x][y]大于dist[x],那么dist[x]就次长链,而当时的次长链(假设为dist[z] + ver[x][z]),就变成了次次长链;之前的 ans = dist[x] + dist[z] + ver[z][x],那么此时的ans = dist[y] + ver[x][y] + dist[x]
  • 所以ans = max(ans,dist[x] + dist[y] + ver[x][y] ),并且我们还得让dist[x]为最长链的长度
  • dist[x] = max(dist[x],dist[y] + ver[x][y])
  • 看一下代码吧~
/*
	这里我用的vector来存储的边和距离
	原型为:	vector<pair<int,int>>v[N]
	st数组的原型为bool st[N]
	dist的原型为	dist[N]
*/

void dp(int u)
{
    dist[u] = 0;
    for(auto &x : v[u])
    {
        int j = x.first,w = x.second;
        if(st[j])continue;
        st[j] = true;
        dp(j);
        ans = max(ans,dist[j] + w + dist[u]);
        dist[u] = max(dist[u],dist[j] + w);
    }
}
//或者是这个代码,原理一样,就是把st数组换成了fa来判断
void dp(int u,int fa)
{
    dist[u] = 0;
    for(auto &x : v[u])
    {
        int j = x.first,w = x.second;
        if(j == fa)continue;
        dp(j,u);
        
        l2 = max(l2,dist[j] + w + dist[u]);
        
        dist[u] = max(dist[u],dist[j] + w);
    }
}

  • 2.DFS或BFS,两者在求得过程中原理是一样的
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值