力扣337. 打家劫舍 III(树形动态规划)

it2023-10-10  63

力扣337. 打家劫舍 III(树形动态规划)

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:                                                                                                          示例 2:

           

 

树形动态规划:

有两点思路需要重点注意:

在设计状态的时候,在后面加一维,消除后效性,打家劫舍第 1 题,股票系列问题 6 个问题,都是这样的思路;树的问题,很多时候采用后序遍历:我们的逻辑是子结点陆续汇报信息给父结点,一层一层向上汇报,最后在根结点汇总值。

每个节点可选择偷或者不偷两种状态,根据题目意思,相连节点不能一起偷

当前节点选择偷时,那么两个孩子节点就不能选择偷了当前节点选择不偷时,两个孩子节点只需要拿最多的钱出来就行(两个孩子节点偷不偷没关系)

我们使用一个大小为 2 的数组来表示 int[] res = new int[2] 0 代表不偷,1 代表偷

任何一个节点能偷到的最大钱的状态可以定义为:

当前节点选择不偷:当前节点能偷到的最大钱数 = 左孩子能偷到的钱 + 右孩子能偷到的钱当前节点选择偷:当前节点能偷到的最大钱数 = 左孩子选择自己不偷时能得到的钱 + 右孩子选择不偷时能得到的钱 + 当前节点的钱数

关键:当前结点「偷」或者「不偷」决定了孩子结点偷或者不偷,把这一点设计成状态,放在第 2 维,这一步叫「消除后效性」,这一点技巧非常常见

// // main.cpp // rob3 // // Created by MXQ on 2020/10/20. // #include <iostream> #include<vector> using namespace std; struct TreeNode { int val; TreeNode *left; TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) {} }; class Solution { public: int rob(TreeNode* root) { vector<int> result(2,0); robnode(root,result); return max(result[0], result[1]); } void robnode(TreeNode* root,vector<int> &result) { if (root==nullptr) { return; } //遍历一次 vector<int> leftresult(2,0); vector<int> rightresult(2,0); robnode(root->left,leftresult); robnode(root->right,rightresult); result[0]=max(leftresult[0],leftresult[1])+max(rightresult[0],rightresult[1]); result[1]=leftresult[0]+rightresult[0]+root->val; } }; int main(int argc, const char * argv[]) { // insert code here... TreeNode p[6] = {3,4,5,1,3,1}; p[0].left=&p[1];p[0].right=&p[2]; p[1].left=&p[3];p[1].right=&p[4]; p[2].right=&p[5]; Solution s; auto result=s.rob(p); std::cout <<result<<endl; std::cout << "Hello, World!\n"; return 0; }

 

最新回复(0)