《算法:生产车间》

生产车间

思路讲解


先以样例来做理解

可以把叶子节点权重看作输出,而其他节点则是能接收多大的值,最后算出根节点能拿到的最大的值

先找到叶子节点并且把能传递的值和多个叶子节点叠加的值存到6节点中

再继续计算2节点能传递的节点值,注意,2和4值都属于6节点,不能相加,这里就涉及到分组问题

最后算出根节点从左右节点中能拿到的最大值

我们总结思路,判断该用什么算法来做:

  • 核心是以链表形式来查找叶子节点已经其他节点所能传递的值
  • 查找每个节点的能传递的值这个过程用到深度搜索dfs
  • 存储每个节点的能传递的值则用到动态规划的分组操作(分组背包)

树形dp

  1. 状态表示:bool dp[s][i]表示:s(son)节点存储了哪些可以传递的值,i是否能向上传递
  2. 状态转移方程:dp[s][i] = dp[s][i] || (dp[x][j] && dp[s][i - j]); s节点的i值是否能向上传递的条件为:两个子节点的值都能向上传递:dp[子节点][子节点的值] && dp[父节点][父节点已经存储的值] (这里已经做了范围处理,不会超过阈值)
  3. 初始化:dp[s[[0] = true : 0值都能向上传递
cpp 复制代码
#include <iostream>
#include <vector>
#include <bitset>
using namespace std;
const int N = 1001;
vector<vector<int>> path(N); //双向存储父子节点的联系
bool dp[N][N];
int n, w[N];

void dfs(int s, int f) {
    dp[s][0] = true;
    if (path[s].size() == 1 && s != 1) { // 1
        dp[s][w[s]] = true;
        return;
    }
    
    for (auto x : path[s]) {
        if (x == f) continue; // 双向存储,如果存储的节点是父节点则跳过
        dfs(x, s);
        
        for (int i = w[s]; i >= 0; i--) { // 2
            for (int j = min(i, w[x]); j >= 0; j--) { // 3
                dp[s][i] = dp[s][i] || (dp[x][j] && dp[s][i - j]);
            }
        }
    }
    return;
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> w[i];
    
    for (int i = 1; i < n; i++) {
        int a, b; cin >> a >> b;
        path[a].emplace_back(b);
        path[b].emplace_back(a);
    }
    
    dfs(1, 0);

    for (int i = w[1]; i >= 0; i--) {
        if (dp[1][i]) {
            cout << i;
            break;
        }
    }
    return 0;
} 

注意事项:

  1. if (path[s].size() == 1 && s != 1)查找该节点是否为叶子节点并且他不是父节点(这里存储做的是双向存储,父节点的节点数也为可能1)
  2. for (int i = w[s]; i >= 0; i--) 先从大到小循环当前要查找的节点它能向上传递的权值
  3. for (int j = min(i, w[x]); j >= 0; j--)再查找它的子节点能向上传递的权重,将它们进行整合存储
cpp 复制代码
#include <iostream>
#include <vector>
#include <bitset>
using namespace std;
const int N = 1001;
vector<vector<int>> path(N);
//bool dp[N][N];
bitset<N> dp[N];
int n, w[N];

void dfs(int s, int f) {
    dp[s][0] = true;
    if (path[s].size() == 1 && s != 1) {
        dp[s][w[s]] = true;
        return;
    }
    
    for (auto x : path[s]) {
        if (x == f) continue;
        dfs(x, s);
        
        // for (int i = w[s]; i >= 0; i--) {
        //     for (int j = min(i, w[x]); j >= 0; j--) {
        //         dp[s][i] = dp[s][i] || (dp[x][j] && dp[s][i - j]);
        //     }
        // }
        bitset<N> f = dp[s];
        for (int i = w[x]; i >= 0; i--) {
            if (dp[x][i]) dp[s] |= f << i;
        }
    }
    return;
}

int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> w[i];
    
    for (int i = 1; i < n; i++) {
        int a, b; cin >> a >> b;
        path[a].emplace_back(b);
        path[b].emplace_back(a);
    }
    
    dfs(1, 0);

    for (int i = w[1]; i >= 0; i--) {
        if (dp[1][i]) {
            cout << i;
            break;
        }
    }
    return 0;
} 
相关推荐
All for pursuit.27 分钟前
【回溯-7】494.目标和
数据结构·c++·算法·leetcode
白杨尚青28 分钟前
C++入门篇(十三):vector(上)——动态数组:构造、空间增长与迭代器失效
开发语言·c++·笔记·算法·stl
Jasmine_llq29 分钟前
《P17461 [GESP202609 八级] 生成树计数》
算法·栈·tarjan 算法·边双连通分量·深度优先搜索 dfs·tarjan 保存当前路径节点·模乘法
Jasmine_llq31 分钟前
《P17462 [GESP202609 八级] 末班车》
算法·dijkstra 算法·最大化版本,求最长可行值·建反向图(逆图 / 反转边)·多源 dijkstra 思想·对每个终点单独跑一遍djst·离线预处理 + 在线查询
the3clipse1 小时前
H.265熵编码核心:CABAC自适应二进制算术编码详解——如何将语法元素高效压缩为比特流
人工智能·算法·视频编码·h.265·hevc·cabac·cavlc
CQU_JIAKE1 小时前
10.4【A】
算法
Godspeed Zhao2 小时前
现代智能雷达技术19——算法(5)
算法
(Charon)2 小时前
【C++面试】RAII到底是什么:从资源管理理解C++对象生命周期
c++·算法·面试
Omics Pro2 小时前
之江实验室NAR|虚拟细胞3阶段训练范式
数据库·人工智能·算法·机器学习·自然语言处理
Tisfy2 小时前
LeetCode 0678.有效的括号字符串:O(n)+O(1)一次遍历
算法·leetcode·字符串·题解·贪心·括号匹配