问题
给定一个有 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的节点把硬币往下传递就可以了,需要注意的点是要优先保证硬币向上传递,也就是父节点没有硬币的时候先保证硬币传递给父节点,因为使用的是深度优先搜索,硬币默认是向下传递的,父节点如果没有硬币只有子节点可以传递过去。