前言
树状DP 要比 在数组上或在矩阵上的 DP 要简单,因为,在树的结构上,总是从子节点推到父节点的。
树状DP 难点是 由可能性得到的返回值类型。
在一棵树中,找结点值的最大和最小
可以对树进行一次遍历,在树中找到最大最小值。
我们也可以用树状DP来完成。当前结点的最值 由当前结点的值,和左孩子的最值 和 右孩子的最值决定。
struct Node{
int value;
Node *left = NULL;
Node *right = NULL;
Node(int data){
value = data;
}
};
struct ReturnData
{
int max, min;
ReturnData(int Min, int Max){
min = Min;
max = Max;
}
};
ReturnData process(Node *head)
{
if (head == NULL){
return ReturnData(INT_MAX, INT_MIN);
}//if
ReturnData leftData = process(head->left);
ReturnData rightData = process(head->right);
return ReturnData(
min(min(leftData.min, rightData.min),head->value),
max(max(leftData.max, rightData.max), head->value));
}
void PrintTree(Node *root, int nLayer)
{
if (root == NULL){
return;
}
PrintTree(root->right, nLayer + 3);
for (int i = 0; i < nLayer; i++){
printf(" ");
}
printf("%d\n", root->value);
PrintTree(root->left, nLayer + 3);
}
void DeteleNode(Node* head)
{
if (head == NULL){
return;
}
DeteleNode(head->left);
DeteleNode(head->right);
delete head;
}
int main()
{
Node* head = new Node(6);
head->left = new Node(1);
head->left->left = new Node(1);
head->left->right = new Node(3);
head->right = new Node(12);
head->right->left = new Node(10);
head->right->left->left = new Node(4);
head->right->left->left->left = new Node(2);
head->right->left->left->right = new Node(5);
head->right->left->right = new Node(14);
head->right->left->right->left = new Node(11);
head->right->left->right->right = new Node(15);
head->right->right = new Node(13);
head->right->right->left = new Node(20);
head->right->right->right = new Node(16);
PrintTree(head,0);
ReturnData result = process(head);
cout << result.max << " " << result.min << endl;
DeteleNode(head);
return 0;
}
在一棵树中,求其中的最大二叉搜索子树
子树的概念:在一个根结点下,下边的后代结点都要有。
拓扑结构:在一个根结点下,下边的后代结点不一定都有。
题解:从小到大找子树是否为二叉搜索子树。在当前结点中,看看结点左孩子的最大二叉搜索子树 , 和结点的右孩子的最大二叉搜索子树,取最大值。如果当前结点左孩子的最大二叉搜索子树的头结点是它本身,当前结点右孩子的最大二叉搜索子树的头结点是它本身,说明可能要产生更大的二叉搜索子树了。
struct Node{
int value;
Node *left = NULL;
Node *right = NULL;
Node(int data){
value = data;
}
};
struct ReturnType
{
int size;
Node *head;
int min, max;
ReturnType(int a, Node *b, int c, int d){
size = a;
head = b;
min = c;
max = d;
}
};
ReturnType process(Node *head)
{
if (head == NULL){
return ReturnType(0, NULL, INT_MAX, INT_MIN);
}
Node *left = head->left;
ReturnType leftSubTreeInfo = process(left);
Node *right = head->right;
ReturnType rightSubTreeInfo = process(right);
int includeltSelf = 0;
if (leftSubTreeInfo.head == left
&& rightSubTreeInfo.head == right
&& head->value > leftSubTreeInfo.max
&& head->value < rightSubTreeInfo.min
){
includeltSelf = leftSubTreeInfo.size + rightSubTreeInfo.size + 1;
}//if
int p1 = leftSubTreeInfo.size;
int p2 = rightSubTreeInfo.size;
int maxSize = max(max(p1, p2), includeltSelf);
Node* maxHead = p1 > p2 ? leftSubTreeInfo.head : rightSubTreeInfo.head;
if (maxSize == includeltSelf){
maxHead = head;
}//if
return ReturnType(maxSize, maxHead,
min(min(leftSubTreeInfo.min, rightSubTreeInfo.min), head->value),
max(max(leftSubTreeInfo.max, rightSubTreeInfo.max), head->value));
}
void PrintTree(Node *root, int nLayer)
{
if (root == NULL){
return;
}
PrintTree(root->right, nLayer + 3);
for (int i = 0; i < nLayer; i++){
printf(" ");
}
printf("%d\n", root->value);
PrintTree(root->left, nLayer + 3);
}
void DeteleNode(Node* head)
{
if (head == NULL){
return;
}
DeteleNode(head->left);
DeteleNode(head->right);
delete head;
}
int main()
{
Node* head = new Node(6);
head->left = new Node(1);
head->left->left = new Node(0);
head->left->right = new Node(3);
head->right = new Node(12);
head->right->left = new Node(10);
head->right->left->left = new Node(4);
head->right->left->left->left = new Node(2);
head->right->left->left->right = new Node(5);
head->right->left->right = new Node(14);
head->right->left->right->left = new Node(11);
head->right->left->right->right = new Node(15);
head->right->right = new Node(13);
head->right->right->left = new Node(20);
head->right->right->right = new Node(16);
PrintTree(head, 0);
ReturnType bst = process(head);
cout << endl << endl;
PrintTree(bst.head, 0);
DeteleNode(head);
return 0;
}
求一个树上的最远距离
节点A 走到 节点B 的距离为:A 走到 B最短路径上的节点个数。
题解:返回类型为由该节点和该节点的所有子孙节点构成的子树 的 最远距离, 和该结点的高度。
struct Node{
int value;
Node *left = NULL;
Node *right = NULL;
Node(int data){
value = data;
}
};
struct ReturnType
{
int maxDistance;
int h;
ReturnType(int a, int b) :maxDistance(a), h(b){}
};
ReturnType process(Node *head)
{
if (head == NULL){
return ReturnType(0,0);
}//if
ReturnType leftReturnType = process(head->left);
ReturnType rightReturnType = process(head->right);
int includeHeadDistance = leftReturnType.h + rightReturnType.h + 1;
int p1 = leftReturnType.maxDistance;
int p2 = rightReturnType.maxDistance;
int resultDistance = max(max(p1, p2), includeHeadDistance);
int curHeight = max(leftReturnType.h, rightReturnType.h) + 1;
return ReturnType(resultDistance,curHeight);
}
void PrintTree(Node *root, int nLayer)
{
if (root == NULL){
return;
}
PrintTree(root->right, nLayer + 3);
for (int i = 0; i < nLayer; i++){
printf(" ");
}
printf("%d\n", root->value);
PrintTree(root->left, nLayer + 3);
}
void DeteleNode(Node* head)
{
if (head == NULL){
return;
}
DeteleNode(head->left);
DeteleNode(head->right);
delete head;
}
int main()
{
Node* head = new Node(6);
head->left = new Node(1);
head->left->left = new Node(1);
head->left->right = new Node(3);
head->right = new Node(12);
head->right->left = new Node(10);
head->right->left->left = new Node(4);
head->right->left->left->left = new Node(2);
head->right->left->left->right = new Node(5);
head->right->left->right = new Node(14);
head->right->left->right->left = new Node(11);
head->right->left->right->right = new Node(15);
head->right->right = new Node(13);
head->right->right->left = new Node(20);
head->right->right->right = new Node(16);
PrintTree(head,0);
ReturnType result = process(head);
cout << result.maxDistance << " " << result.h << endl;
DeteleNode(head);
return 0;
}
最大高兴度
题目:
公司开party ,有这样一个规定,一个员工来了,那么它的直接上级和直接下级不可以来,每个员工对参加party 都有各自的高兴度。给你一个树状的员工职位表,要你决定谁来,谁不来,并且总高兴度要最大。
题解:
每个节点上有两种可能性,1.该节点来了,以这个节点为根的子树的最大高兴度。
2.该节点没来了,以这个节点为根的子树的最大高兴度。
所以我们的返回数据定义为了
struct ReturnType
{
int come_MaxHappy;
int notCome_MaxHappy;
ReturnType(int a = 0, int b = 0) :come_MaxHappy(a), notCome_MaxHappy(b){}
};
再由这个返回数据 推出 它的祖先节点的返回数据。
struct Node{
int happyFactor;
vector<Node*> nexts;
Node(int a){
happyFactor = a;
}
};
struct ReturnType
{
int come_MaxHappy;
int notCome_MaxHappy;
ReturnType(int a = 0, int b = 0) :come_MaxHappy(a), notCome_MaxHappy(b){}
};
ReturnType process(Node *head)
{
int come_MaxHappy = 0;
int notCome_MaxHappy = 0;
Node* next = NULL;
ReturnType nextData;
for (int i = 0; i < head->nexts.size(); i++){
next = head->nexts[i];
nextData = process(next);
come_MaxHappy += nextData.notCome_MaxHappy;
notCome_MaxHappy += max(nextData.come_MaxHappy, nextData.notCome_MaxHappy);
}//for
return ReturnType(come_MaxHappy,notCome_MaxHappy);
}
判断一棵树是否为平衡二叉树
题解:可能性,返回一个树是否是平衡的,以及该树的高度。它的父节点拿到这些信息后,如果它的子树是不平衡的,那么,整棵树一定不平衡。如果它的子树是平衡的, 那么我们用 右子树的高度减去 左子树的高度...
struct Node{
int value;
Node *left = NULL;
Node *right = NULL;
Node(int a){
value = a;
}
};
struct ReturnType
{
bool isBalance;
int h;
ReturnType(bool a, int b){
isBalance = a;
h = b;
}
};
ReturnType process(Node *head)
{
if (head == NULL){
return ReturnType(true, 0);
}
ReturnType leftData = process(head->left);
if (leftData.isBalance == false){
return ReturnType(false, 0);
}//if
ReturnType rightData = process(head->right);
if (rightData.isBalance == false){
return ReturnType(false, 0);
}//if
if (abs(rightData.h - leftData.h) > 1){
return ReturnType(false, 0);
}//if
return ReturnType(true, max(leftData.h, rightData.h) + 1);
}
void PrintTree(Node *root, int nLayer)
{
if (root == NULL){
return;
}
PrintTree(root->right, nLayer + 3);
for (int i = 0; i < nLayer; i++){
printf(" ");
}
printf("%d\n", root->value);
PrintTree(root->left, nLayer + 3);
}
void DeteleNode(Node* head)
{
if (head == NULL){
return;
}
DeteleNode(head->left);
DeteleNode(head->right);
delete head;
}
int main()
{
Node* head = new Node(6);
head->left = new Node(1);
head->left->left = new Node(1);
head->left->right = new Node(3);
head->right = new Node(12);
head->right->left = new Node(10);
head->right->left->left = new Node(4);
head->right->left->left->left = new Node(2);
head->right->left->left->right = new Node(5);
head->right->left->right = new Node(14);
head->right->left->right->left = new Node(11);
head->right->left->right->right = new Node(15);
head->right->right = new Node(13);
head->right->right->left = new Node(20);
head->right->right->right = new Node(16);
PrintTree(head, 0);
ReturnType result = process(head);
cout << endl << endl;
cout << result.isBalance << endl;
DeteleNode(head);
return 0;
}