左神算法学习日记——树dp

树dp问题只需要考虑每个结点的所有孩子的情况就可以解决 

class Node
{
public:
	int num;
	Node* left;
	Node* right;
	Node() = default;
	Node(int n)
	{
		num = n;
	}
	~Node()
	{
		queue del;
		Node* temp;
		del.push(this);
		while (!del.empty() && del.front())
		{
			temp = del.front();
			del.pop();
			if (temp->left)
				del.push(temp->left);
			if (temp->right)
				del.push(temp->right);
			delete temp;
		}
	}
};

class treeinf
{
public:
	int max;
	int min;
	Node* head;
	int size;
	treeinf(int b, int s, Node* node, int maxn)
	{
		max = b;
		min = s;
		head = node;
		size = maxn;
	}
}; 
void creat(Node* node)
{
	if (!node)
		return;
	int l = 0, r = 0;
	cin >> l >> r;
	if (l)
	{
		node->left = new Node(l);
		creat(node->left);
	}
	if (r)
	{
		node->right = new Node(r);
		creat(node->right);
	}
}
//获得子树中结点最多的搜索二叉树的结点个数
treeinf* getmaxNode(Node* node)
{
        //这个问题可以拆分为以每个子树为对象的子问题,且对每个子树的处理方式相同
	if (!node)//以当前子树为空树时为basecase
	{
		return new treeinf(INT_MIN, INT_MAX, NULL, 0);
	}
	treeinf* leftinf = getmaxNode(node->left);//获取左子树的信息
	treeinf* rightinf = getmaxNode(node->right);//获取右子树的信息
	int curNum = 0;
        //对于每个子问题主要根据两种情况进行决策:1.整个左子树和整个右子树是搜索二叉树,2.左/右子树的子树为结点最多的搜索二叉树。
        //根据这两种情况进行判断:当左右子树都是搜索二叉树时,整个树根据左子树的最大值和右子树的最小值来决定结点个数是否+1;
        //当其中一个子树不是搜索二叉树时,则根据左右子树的最大搜索子树的结点个数进行决策。为此我们需要:最大搜索子树的头结点,子树的最大值和最小值,最大结点个数
	if (node->left == leftinf->head
		&&node->right == rightinf->head
		&&node->num > leftinf->max
		&&node->num < rightinf->min)
		curNum = leftinf->size + rightinf->size + 1;
	int maxnode = max(curNum, max(leftinf->size, rightinf->size));//第一种情况,同时判断当前树是否为搜索二叉树
	Node* maxhead = leftinf->size>rightinf->size?leftinf->head:rightinf->head;//第二种情况,获得最大搜索子树的头结点
	if (curNum)
		maxhead = node;
	return new treeinf(max(rightinf->max node->num),//获得最大值,最大值只有整棵树为搜索二叉树时才会用,因此我们这里假设当前子树是搜索二叉树
		min(min(leftinf->min, node->num),//获得最小值
		maxhead, maxnode);
}

class returninf
{
public:
	int distance;
	int height;
	returninf(int d, int h)
	{
		distance = d;
		height = h;
	}
};
//求一个树中距离最远的两个点之间的距离是多少,距离定义为从一个点到另一个点所要经过的点的个数,包括起始点本身。
returninf* maxdis(Node* node)
{
        //划分为以每个子树为对象的子问题,最大距离可能存在于当前树的左子树中,也可能存在于当前树的右子树中,也可能是经过了当前根节点的路径中
	if (!node)
		return new returninf(0, 0);//basecase即空树,最大距离为0,高度为0,以这个basecase为基础,对其他子树的处理方式相同:需要在三种可能性中找出最大的距离作为当前子树的最大距离
	returninf* leftinf = maxdis(node->left);
	returninf* rightinf = maxdis(node->right);
	int curdis = leftinf->height + rightinf->height+1;
	int maxdis = max(max(leftinf->distance, rightinf->distance), curdis);
	return new returninf(maxdis, max(leftinf->height, rightinf->height) + 1);
}

class actnode
{
public:
	int active;
	vector nexts;
	actnode()
	{
		active = 0;
		nexts = vector();
	}
};

class returnact
{
public:
	int inactive;
	int offactive;
	returnact(int i, int o)
	{
		inactive = i;
		offactive = o;
	}
};
//组织活动,员工的上一级领导在该员工必定不会参加,问怎么邀请员工可以保障活跃的最高
returnact* getmaxact(actnode* head)
{
        //初始化就是basecase
	int inact = head->active;
	int offact = 0;
        //对于每一个子树,当前根节点的参加活跃度为它所有子节点不参加活跃度的和加上该节点参加的活跃度,当前结点的不参加活跃度为它所有子节点的参加和不参加活跃的的最大值的和
	for (auto var : head->nexts)
	{
		returnact* nextinf = getmaxact(var);
		inact += nextinf->offactive;
		offact += max(nextinf->inactive, nextinf->offactive);
	}
	return new returnact(inact, offact);
}

 

你可能感兴趣的:(学习日记,c++)