【C++算法】二叉树

问题

给定一个有 N 个结点的二叉树根结点 root,树中的每个结点上都对应有 node.val 枚硬币,并且总共有 N 枚硬币。 在一次移动中,我们可以选择两个相邻的结点然后将一枚硬币从其中一个节 点移动到另一个结点。 (移动可以是从父结点到子节点,或者从子节点移动到父 节点 )。为确保尽可能多的节点都拥有至少一个硬币,至少需要移动几次硬币?

分析

        首先根据题意,这道题目就是移动硬币给其父节点或子节点,在确保自身拥有至少一枚硬币的前提下,把自己多的硬币先传给自己的父节点,如果还有多,再传给自己的子节点,因为二叉树的遍历是从上往下遍历的,自己的父节点若没有硬币,那么只能由自己给,但是自己的子节点没有硬币,可以由子节点的子节点提供,所以优先保证父节点也能拥有硬币,这样就能保证更多的节点拥有硬币。

       代码思路如下:

       首先需要创造一棵二叉树,这里以题目例子为例创造了一棵二叉树,之后我们采用深度优先遍历,递归终止条件为遍历到叶子节点的时候停止递归,每次递归,只要当前节点的硬币数大于1,就让他把硬币优先传给自己的父节点,传出去的硬币越多,才能保证有更多的节点能获得硬币。再保证父节点有一个硬币的情况下,可以把多的硬币传给自己的子节点。除此之外,还要记得用一个变量flag来记录传递次数。

代码和运行结果

# include <bits/stdc++.h>
using namespace std;

struct bintree
{
	int data;
	struct bintree* pleft;
	struct bintree* pright;
	struct bintree* parent;
};

int flag;

struct bintree* createtree(void)
{
	struct bintree* pa = (struct bintree*)malloc(sizeof(struct bintree));
	struct bintree* pb = (struct bintree*)malloc(sizeof(struct bintree));
	struct bintree* pc = (struct bintree*)malloc(sizeof(struct bintree));

	pa->data = 3;  //给数据域赋值 
	pb->data = 0;
	pc->data = 0;

	pa->pleft = pb;  //设定每个节点的指针域 
	pa->pright = pc;
	pa->parent = NULL;
	pb->parent = pa;
	pc->parent = pa;
	pb->pleft = NULL;
	pb->pright = NULL;
	pc->pleft = NULL;
	pc->pright = NULL;


	return pa;
}

void DFS(struct bintree* p)
{
	if (p == NULL)
		return;
	while (p->data > 1)
	{
		if (p->parent != NULL && p->parent->data == 0)
		{
			p->data--;
			p->parent->data++;
			flag++;
		}
		else if (p->pleft != NULL && p->pleft->data == 0)
		{
			p->data--;
			p->pleft->data++;
			flag++;
		}
		else if (p->pright != NULL && p->pright->data == 0)
		{
			p->data--;
			p->pright->data++;
			flag++;
		}
		else
			break;
	}
	DFS(p->pleft);
	DFS(p->pright);
	return;
}

int main(void)
{
	struct bintree* ptop = createtree();
	DFS(ptop);
	cout << "移动次数为:"<<flag << endl;
	

	return 0;
}

硬币传递问题,其实本质上就是搜索二叉树的问题,所以只需要利用深度优先搜索把二叉树进行遍历,让硬币数大于1的节点把硬币往下传递就可以了,需要注意的点是要优先保证硬币向上传递,也就是父节点没有硬币的时候先保证硬币传递给父节点,因为使用的是深度优先搜索,硬币默认是向下传递的,父节点如果没有硬币只有子节点可以传递过去。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值