洛谷P3574 [POI2014] FAR-FarmCraft(树形dp)

洛谷 P 3574 [ P O I 2014 ] F A R − F a r m C r a f t (树形 d p ) \Huge{洛谷P3574 [POI2014] FAR-FarmCraft(树形dp)} 洛谷P3574[POI2014]FAR−FarmCraft(树形dp)

文章目录

题目链接:P3574 [POI2014] FAR-FarmCraft - 洛谷

题意

给出 n n n个节点、 n − 1 n-1 n−1条边的一棵无根树;经过每条边所用时间都为 1 1 1。然后每个节点都有点权 b [ i ] b[i] b[i]。

题目故事:管理员从自己家(一号节点)出发,然后将一批电脑分发给每个节点的居民,每个居民得到电脑后会立即开始下载游戏,下载游戏的时间为点权 b [ i ] b[i] b[i]。

管理员每次经过某节点就相当于直接分发给居民。

管理员的车恰好能够走每条路两遍。

要求计算出管理员从开始配送到所有居民都能玩上游戏所用最少时间。

题目说明

给一棵树,走过每条边需要花费一个时间,安装软件又需要花费一个时间,需要遍历整棵树并回到起点,想让所有点中到达时间+安装时间的最大值最小,问这个值是多少?

思路

跟据题目要求,显然能够知道,题目要求求出所有居民中最后玩上游戏的居民所用时间,并且要求这个时间最小。

跟据题目说明 ,我们可以想到:对于同一个节点的子节点,大致的贪心思路是先遍历点权最大的节点

但是可能会出现一种情况(画的比较丑陋,多多见谅):

但是我们可以注意到题目有限制条件**"管理员的车恰好能够走每条路两遍"**,那么我们就不用考虑这种情况了。

一般地,我们用 f [ i ] f[i] f[i]表示节点 i i i这棵子树中的最大值 , d e p [ i ] dep[i] dep[i]表示从节点 i i i出发遍历其子树并返回所用的总时间 , b [ i ] b[i] b[i]表示点权

容易发现,这道题属于树形dp中的选择节点型,只不过需要判断的是选择子节点的先后顺序。

那么对应的状态转移方程即为:
f [ x ] = max ⁡ ( f [ x ] , d e p [ x ] + max ⁡ ( f [ i ] , f [ j ] + d e p [ i ] + 2 ) + 1 ) f[x]=\max(f[x], dep[x]+\max(f[i],f[j]+dep[i]+2)+1) f[x]=max(f[x],dep[x]+max(f[i],f[j]+dep[i]+2)+1)

其中 x x x为当前节点, i , j i,j i,j表示它的其中两个子节点。需要解释一下:

  • 方程中的+2是因为从一个子节点到另一个子节点的两段路。
  • 方程中的+1是因为从 x x x节点到子节点的一段路。

但是该这样进行状态转移,我们需要对子节点相互比较,其时间复杂度为 O ( n 2 ) O(n^2) O(n2),会超时。

我们考虑优化状态转移方程:

  • 如果先 i i i后 j j j: max ⁡ ( f [ i ] , f [ j ] + d e p [ i ] + 2 ) \max(f[i],f[j]+dep[i]+2) max(f[i],f[j]+dep[i]+2)

  • 如果先 j j j后 i i i: max ⁡ ( f [ j ] , f [ i ] + d e p [ j ] + 2 ) \max(f[j],f[i]+dep[j]+2) max(f[j],f[i]+dep[j]+2)

  • 因为 f [ i ] < f [ i ] + d e p [ j ] + 2 f[i] <f[i]+dep[j]+2 f[i]<f[i]+dep[j]+2且 f [ j ] < f [ j ] + d e p [ i ] + 2 f[j]<f[j]+dep[i]+2 f[j]<f[j]+dep[i]+2

  • 原式可化为: max ⁡ ( f [ j ] + d e p [ i ] + 2 , f [ i ] + d e p [ j ] + 2 ) \max(f[j]+dep[i]+2,f[i]+dep[j]+2) max(f[j]+dep[i]+2,f[i]+dep[j]+2)

  • 即为: f [ i ] − d e p [ i ] < f [ j ] − d e p [ j ] f[i]-dep[i]<f[j]-dep[j] f[i]−dep[i]<f[j]−dep[j](当选 j j j时成立)

因此在判断选取子节点时,可以先对子节点按照上述不等式排序,即为选取子节点的先后顺序。

最后需要注意的是,dfs过程中我们并没有判断根节点的时间,需要输出时进行判断取 m a x max max。

标程

cpp 复制代码
#include<bits/stdc++.h>

using namespace std;

#define IOS ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
#define int long long 
#define ULL unsigned long long 
#define PII pair<int, int>
#define lowbit(x) (x & -x)
#define Mid ((l + r) >> 1)
#define ALL(x) x.begin(), x.end()
#define endl '\n'
#define fi first 
#define se second

const int INF = 0x7fffffff;
const int Mod = 1e9 + 7;
const int N = 5e5 + 10;

int n;
vector<int> a[N];
int b[N], dep[N], f[N];

void dfs(int x, int y) {
    if(x != 1) f[x] = b[x];
    for(auto i : a[x]) {
        if(i == y) continue;
        dfs(i, x);
    }
    sort(ALL(a[x]), [](int n1, int n2) {
        return dep[n1] - f[n1] < dep[n2] - f[n2];
    });
    for(auto i : a[x]) {
        if(i == y) continue;
        f[x] = max(f[x], f[i] + dep[x] + 1);
        dep[x] += dep[i] + 2;
    }
}

void Solved() {
    cin >> n;
    for(int i = 1; i <= n; i ++ ) {
        cin >> b[i];
    }
    for(int i = 1; i < n; i ++ ) {
        int x, y; cin >> x >> y;
        a[x].push_back(y); a[y].push_back(x);
    }

    dfs(1, 0);
    
    cout << max(f[1], dep[1] + b[1]) << endl;
}

signed main(void) {
    IOS

    int ALL = 1; 
    // cin >> ALL;
    while(ALL -- ) Solved();
    // cout << fixed;//强制以小数形式显示
    // cout << setprecision(N); //保留n位小数

    return 0;
}
相关推荐
feifeigo1237 分钟前
基于马尔可夫随机场模型的SAR图像变化检测源码实现
算法
fengfuyao98532 分钟前
基于STM32的4轴步进电机加减速控制工程源码(梯形加减速算法)
网络·stm32·算法
无敌昊哥战神2 小时前
深入理解 C 语言:巧妙利用“0地址”手写 offsetof 宏与内存对齐机制
c语言·数据结构·算法
小白菜又菜2 小时前
Leetcode 2075. Decode the Slanted Ciphertext
算法·leetcode·职场和发展
Proxy_ZZ02 小时前
用Matlab绘制BER曲线对比SPA与Min-Sum性能
人工智能·算法·机器学习
黎阳之光2 小时前
黎阳之光:以视频孪生领跑全球,赋能数字孪生水利智能监测新征程
大数据·人工智能·算法·安全·数字孪生
小李子呢02112 小时前
前端八股6---v-model双向绑定
前端·javascript·算法
2301_822703203 小时前
Flutter 框架跨平台鸿蒙开发 - 创意声音合成器应用
算法·flutter·华为·harmonyos·鸿蒙
cmpxr_4 小时前
【C】数组名、函数名的特殊
c语言·算法
KAU的云实验台4 小时前
【算法精解】AIR期刊算法IAGWO:引入速度概念与逆多元二次权重,可应对高维/工程问题(附Matlab源码)
开发语言·算法·matlab