树形dp

题目:二叉树节点间的最大距离问题
从二叉树的节点a出发, 可以向上或者向下走, 但沿途的节点只能经过一次, 到达节点b时路径上的节点个数叫作a到b的距离, 那么二叉树任何两个节点之间都有距离, 求整棵树上的最大距离。

分析

对于树上的任意一个节点,它的最大距离有3种可能性,分别是左子树的最大距离、右子树的最大距离、和左子树的高度加右子树的高度加1。如果该节点最大距离等于左子树的最大距离或右子树的最大距离,只需要得到左子树或右子树的最大距离即可,但如果是第三种可能性,则需要得到左右子树的高度。所以每个节点的左孩子和右孩子都应该返回一种结构,该结构中包括以孩子节点节点为根节点的树的最大距离和树的高度,然后根据获取到的左右孩子的信息,选择出自己的最大距离和高度。

代码实现

#include 

using namespace std;

struct node{
    int data;
    node* left;
    node* right;
    node(int data){
        this->data = data;
        this->left = NULL;
        this->right = NULL;
    }
};

struct Info{
    int maxDistance;
    int height;
    Info(int md,int h){
        maxDistance = md;
        height = h;
    }
};

Info* process(node* root){
    if(root == NULL){
        return new Info(0,0);
    }

    Info* leftInfo = process(root->left);
    Info* rightInfo = process(root->right);

    int maxDistance = max(max(leftInfo->maxDistance,rightInfo->maxDistance),leftInfo->height + rightInfo->height + 1);
    int height = max(leftInfo->height,rightInfo->height) + 1;

    return new Info(maxDistance,height);
}

int getMaxDistance(node* root){
    return process(root)->maxDistance;
}


int main()
{
    node* root = new node(1);
    root->left = new node(2);
    root->right = new node(3);
    root->left->left = new node(4);
    root->left->right = new node(5);
    root->right->left = new node(6);
    root->right->right = new node(7);
    root->left->left->left = new node(8);
    root->left->left->right = new node(9);
    root->left->right->left = new node(10);
    root->left->right->right = new node(11);
    root->right->left->left = new node(12);
    root->right->left->right = new node(13);
    root->right->right->left = new node(14);
    root->right->right->right = new node(15);
    cout << getMaxDistance(root) << endl;
    return 0;
}

 

题目:派对的最大快乐值
员工信息的定义如下:
class Employee {
public int happy; // 这名员工可以带来的快乐值
List subordinates; // 这名员工有哪些直接下级
} 公
司的每个员工都符合 Employee 类的描述。 整个公司的人员结构可以看作是一棵标准的、 没有环的
多叉树。 树的头节点是公司唯一的老板。 除老板之外的每个员工都有唯一的直接上级。 叶节点是没有
任何下属的基层员工(subordinates列表为空), 除基层员工外, 每个员工都有一个或多个直接下级。
这个公司现在要办party, 你可以决定哪些员工来, 哪些员工不来。 但是要遵循如下规则。
1.如果某个员工来了, 那么这个员工的所有直接下级都不能来
2.派对的整体快乐值是所有到场员工快乐值的累加
3.你的目标是让派对的整体快乐值尽量大
给定一棵多叉树的头节点boss, 请返回派对的最大快乐值。

分析:该道题目的结构是一颗多叉树。对于这道题目的任意节点,都有两种可能性:该节点代表的员工来或不来。如果该员工来,那么它的下级员工都不能来,所以该节点的最大快乐数应该是该节点本身的快乐数加上它的下级员工都不来的快乐数;如果该员工来,那么该节点的快乐数应该是它的下级员工来或不来中快乐值较大的一项的累加。所以任意节点的子树都应该返回两条信息,来时的快乐值和不来时的快乐值供节点使用。节点根据这些信息构造出自己的来或不来的快乐数。

struct Node{
    int happy;
    list  subordinates;
    Node(int h){
        this->happy = h;
    }
};

struct data{
    int inHappyNum;
    int noHappyNum;
    data(int in,int no){
        inHappyNum = in;
        noHappyNum = no;
    }
};

data* func(Node* root){
    if(root == NULL){
        return new data(0,0);
    }
    int inHappyNum = 0;
    int noHappyNum = root->happy;
    for(list::iterator itea = root->subordinates.begin();itea != root->subordinates.end(); itea++){
        data* tempData = func(*itea);
        inHappyNum += tempData->noHappyNum;
        noHappyNum += max(tempData->inHappyNum,tempData->noHappyNum);
    }
    return new data(inHappyNum,noHappyNum);
}

int getMaxHappy(Node* node){
    data* res = func(node);
    return max(res->inHappyNum,res->noHappyNum);
}

 

树形dp套路总结

使用前提:如果题目求解目标是S规则, 则求解流程可以定成以每一个节点为头节点的子树在S规则下的每一个答案, 并且最终答案一定在其中。

步骤:

  1. 以某个节点X为头节点的子树中, 分析答案有哪些可能性, 并且这种分析是以X的左子树、 X的右子树和X整棵树的角度来考虑可能性的
  2. 根据第一步的可能性分析, 列出所有需要的信息
  3. 合并第二步的信息, 对左树和右树提出同样的要求, 并写出信息结构
  4. 设计递归函数, 递归函数是处理以X为头节点的情况下的答案。包括设计递归的basecase, 默认直接得到左树和右树的所有信息, 以及把可能性做整合, 并且要返回第三步的信息结构这四个小步骤 

你可能感兴趣的:(数据结构,算法与数据结构)