我在微软亚洲研究院面试的一道题,关于二叉树的,欢迎各位讨论

hinyunsin 2011-03-17 11:43:49
加精
假设有一颗二叉树,已知这棵树的节点上不均匀的分布了若干石头,石头数跟这棵二叉树的节点数相同,石头只可以在子节点和父节点之间进行搬运,每次只能搬运一颗石头。请问如何以最少的步骤将石头搬运均匀,使得每个节点上的石头上刚好为1。

这是前两周我在微软亚洲研究院面试的题目,当时提出了几种解法都被否定了,后来也没怎么想明白,特地拿来论坛讨论,欢迎大家积极讨论。
...全文
9223 196 打赏 收藏 转发到动态 举报
写回复
用AI写文章
196 条回复
切换为时间正序
请发表友善的回复…
发表回复
software_artisan 2011-06-03
  • 打赏
  • 举报
回复
首先是二叉树,其次是每结点1个。
那么解决方法很明确了,遇到一个石子多于1的节点,就判断此节点下的两个节点下是否存在石子总数小于节点数的,如果有,则标志一个移动方向。如果是大于,则标志为向上移动。等于则无需标记。直至达到末端,那么所有的移动方向都标记出来了。从根节点开始按向上优先回溯,然后按标记方向搬运即可。
pingdan32 2011-06-03
  • 打赏
  • 举报
回复
哈哈~~~在
中间的 ][ 之间插入插入代码即可~~~~~

[Quote=引用 49 楼 2608 的回复:]
kao~~~, 到底怎么插入代码啊!!
[/Quote]
Debugcool 2011-06-02
  • 打赏
  • 举报
回复
这个可以用网络流来做~

第一步,LCA求出树中任意两点的最近公共祖先,那么可以知道任意两点之间的距离。

第二步,建立网络流模型,有多余石子的点在一边,没有石子的在一边,中间连边,容量为剩余石子数,费用为第一步求出的最短距离,然后最小费用流求解~
wangyangkobe 2011-06-02
  • 打赏
  • 举报
回复
编程之美上的
cug_fish_2009 2011-05-31
  • 打赏
  • 举报
回复
此题思路就是树形DP。
  • 打赏
  • 举报
回复
看来没有标准!!
ffee123123 2011-04-12
  • 打赏
  • 举报
回复
这是我想到的一个思路,提供大家一起讨论
i)后根遍历这个二叉树,给每个以某一节点为根的子树的根节点赋一个权值,当这个子树差一个石头时,为-1,多一个石头时为1,不差的时候为0;
ii)找出权值最大的节点node,如果权值为0,结束;否则,将它上面的石头搬运到以它为根的子树的节点上去,将多余的石头移动到父节点,同时修改父节点的权值,并且将以节点node为根的子树逻辑删除。
iii)转回去执行ii
xr19251 2011-04-12
  • 打赏
  • 举报
回复
结贴在哪哦,我想看看 答案~
myhaofana 2011-04-12
  • 打赏
  • 举报
回复
eh....我想到的是一个最小费用最大流的模型........石头-节点.......呵呵...............
迷世书童 2011-04-10
  • 打赏
  • 举报
回复
一提微软
大家精神一振啊
哈哈哈哈
Oo纳兰筱DoO 2011-04-07
  • 打赏
  • 举报
回复
学习一下,见识一下面试题
Torey 2011-04-04
  • 打赏
  • 举报
回复
#include "string.h"
#include<stdio.h>
#include<vector>
#include <math.h>
#include <iostream>
using namespace std;

struct Number_pearl
{
Number_pearl *FatherPo;
Number_pearl *RightChildPo;
Number_pearl *LeftChildPo;
int ResultNumber;
};
void build(Number_pearl* &t,Number_pearl* &tt,int data[], int n)
{
if (t==NULL)
{
t = new Number_pearl;
t->LeftChildPo=NULL;
t->FatherPo=NULL;
t->RightChildPo=NULL;
t->ResultNumber=data[n];
if (tt!=NULL)
{
t->FatherPo=tt;
}
}
if ((n*2+1)<18)
build(t->LeftChildPo,t,data,n*2+1);
if ((n*2+2)<18)
build(t->RightChildPo,t,data,n*2+2);

}


int Map_Number_pearl(Number_pearl *Po)
{
int x=0;
if (Po->RightChildPo!=NULL)
{
x+=Map_Number_pearl(Po->RightChildPo);
};
if (Po->LeftChildPo!=NULL)
{
x+=Map_Number_pearl(Po->LeftChildPo);
};
if (Po->ResultNumber>1)
{
x+=(Po->ResultNumber-1);
if (Po->FatherPo!=NULL)
(Po->FatherPo)->ResultNumber+=(Po->ResultNumber-1);
Po->ResultNumber=1;
}
else if (Po->ResultNumber<1)
{
x+=(1-Po->ResultNumber);
if (Po->FatherPo!=NULL)
(Po->FatherPo)->ResultNumber-=(1-Po->ResultNumber);
Po->ResultNumber=1;
}
return x;
}
int main()
{
// Number_pearl *Po;
//Number_pearl *Po=new Number_pearl;
int data[18]={3,0,0,3,7,0,0,0,0,1,1,1,1,0,0,0,1,0};
Number_pearl *t=NULL;
Number_pearl *tt=NULL;
build(t, tt, data, 0);
cout << Map_Number_pearl(t) << endl;


return 0;


}
Torey 2011-04-04
  • 打赏
  • 举报
回复
后序遍历
证明:
在一棵只有三个节点的子二叉树里,石头在子树里搬运的步数肯定小于等于子树外面节点搬运的步数。
石头由一个子树移到另一个子数可归结为两步,一为石头移到父节点,二为石头由父节点移到子树结点,所以无论哪颗石头移到哪个节点,总步数总是一定。
Torey 2011-04-04
  • 打赏
  • 举报
回复
楼上负数这个概念很好,只是计算部数,根本不用考虑路径
疯狂的烤冰 2011-04-02
  • 打赏
  • 举报
回复
下面是我的一些想法,是递归的思想:
首先,如果叶子节点的石头多于一个的话,那么就将多出来的转移个父亲节点,这个是必须的,没有其他方法。同理,如果叶子节点的石头为0个的话,就必须将从父亲节点向其移动一个。不管其父亲节点有没有石头,都将其石头的数目减1,就是说其可以是负数,如果是负数,等待从其他节点移动过来石头。
这样的话,如果后序遍历二叉树,那么遍历到每个节点,如果其石头数目大于1,就将多余的移动到其父亲节点,因为其子树已经满足要求了,同理,如果数目小于1,就从其父亲节点减去相应的石头数。由于每一步都是必须的,所以这样的移动的次数应该最少的。
下面是用c++的代码的实现。



#include <iostream>
#include <math.h>
using namespace std;

struct tree //二叉树的结构
{
int num; //石头的数量
tree *left, *right, *parent; //左右和双亲节点
};

tree* build(int data[], int n)
/*建树的函数,data是存石头数量的数组,按从上到下的顺序存储,
如果有空节点则用-1代替,n是节点个数(空节点也算),返回值是树根。(我写的可能不太好,大家可以自己实现)
*/
{
int i;
tree* t[999];
for(i = 0; i < n; i++)
{
if(data[i] != -1)
{
t[i] = new tree;
t[i]->num = data[i];
t[i]->left = t[i]->right = t[i]->parent = NULL;
}
else t[i] = NULL;
}
for(i = 0; i < n; i++)
if(t[i])
{
if(2*i+1>=n)
t[i]->left = t[i]->right = NULL;
else
{
t[i]->left = t[2*i+1];
t[i]->right = t[2*i+2];
}
if(i)
t[i]->parent = t[(i-1)/2];
else
t[i]->parent = NULL;
}
return t[0];
}

//主要的算法,返回这棵树需要移动几步
int move(tree *t)
{
int x = 0;
if(t)
{
x += move(t->left)+move(t->right); //左右子树需要移动的步数
if(t->parent)
{
t->parent->num += (t->num-1); //从双亲节点移来或移走石头
x += abs(t->num-1); //加上本节点需要移动的次数
t->num = 1;
}
}
return x;
}

int main()
{
int data[999], n = 0;
while(cin >> n)
{
int i;
for(i = 0; i < n; i++)
cin >> data[i];
tree *t = build(data, n);
cout << move(t) << endl;
}

return 0;
}
qq675927952 2011-03-31
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 dengsf 的回复:]
貌似后序遍历一次即可。
以下未调试,但应够清楚。


C/C++ code

//节点结构
struct node{
int rock_num; //节点原有石头数
node *p_left;
node *p_right;
};

int g_total_move = 0;

//计算本子树需和外部交互的石头数。不足传入,有多传出
void calc_……
[/Quote]

正解!
hxlandcym 2011-03-31
  • 打赏
  • 举报
回复
构造二叉树比如四级1表示存在,0表示不存在,因为只有两个分支。
10000000
10001000
10100010
11010010
定义数组表示二叉树的数据,比如此列int a[]=new int [16];
for(int i=0;i<4;i+=2)
t[k-1][i]=t[k-1][i]+t[k][i]-1+t[k][i+1]-1;
for(int i=1;i<16;i++)s[0]+=ABS(a[i]-1);
hxlandcym 2011-03-31
  • 打赏
  • 举报
回复
构造二叉树比如四级1表示存在,0表示不存在,因为只有两个分支。
10000000
10001000
10100010
11010010
定义数组表示二叉树的数据,比如此列int a[]=new int [15];
for(int i=0;i<4;i+=2)
t[k-1][i]=t[k-1][i]+t[k][i]-1+t[k][i+1]-1;
for(int i=0;i<15;i++)s+=ABS(a[5]);
wesweeky 2011-03-31
  • 打赏
  • 举报
回复
好难啊。。。
Torey 2011-03-30
  • 打赏
  • 举报
回复
明天写在不同子二叉树里搬运石头的证明
加载更多回复(127)
目录 第1章 一大波数正在靠近——排序 1 第1节 zui快zui简单的排序——桶排序 2 第2节 邻居好说话——冒泡排序 7 第3节 zui常用的排序——快速排序 12 第4节 小哼买书 20 第2章 栈、队列、链表 25 第1节 解密QQ号——队列 26 第2节 解密回文——栈 32 第3节 纸牌游戏——小猫钓鱼 35 第4节 链表 44 第5节 模拟链表 54 第3章 枚举!很暴力 57 第1节 坑爹的奥数 58 第2节 炸弹人 61 第3节 火柴棍等式 67 第4节 数的全排列 70 第4章 wan能的搜索 72 第1节 不撞南墙不回头——深度优先搜索 73 第2节 解救小哈 81 第3节 层层递进——广度优先搜索 88 第4节 再解炸弹人 95 第5节 宝岛探险 106 第6节 水管工游戏 117 第5章 图的遍历 128 第1节 深度和广度优先究竟是指啥 129 第2节 城市地图——图的深度优先遍历 136 第3节 zui少转机——图的广度优先遍历 142 第6章 zui短路径 147 第1节 只有五行的算法——Floyd-Warshall 148 第2节 Dijkstra算法——通过边实现松弛 155 第3节 Bellman-Ford——解决负权边 163 第4节 Bellman-Ford的队列优化 171 第5节 zui短路径算法对比分析 177 第7章 神奇的树 178 第1节 开启“树”之旅 179 第2节 二叉树 183 第3节 堆——神奇的优先队列 185 第4节 擒贼先擒王——并查集 200 第8章 更多精彩算法 211 第1节 镖局运镖——图的zui小生成树 212 第2节 再谈zui小生成树 219 第3节 重要城市——图的割点 229 第4节 关键道路——图的割边 234 第5节 我要做月老——二分图zui大匹配 237 第9章 还能更好吗——微软亚洲研究院面试 243 啊哈算法 目 录 第1章 编程改变思维 1 第1节 为什么要学习编程 1 第2节 本书是讲什么的,写给谁看的 4 第2章 梦想启航 7 第1节 编程的魔力 7 第2节 让计算机开口说话 9 第3节 多彩一点 18 第4节 让计算机做加法 21 第5节 数字的家――变量 26 第6节 数据输出――我说咋地就咋地 31 第7节 数据输入――我说算啥就算啥 33 第8节 究竟有多少种小房子 37 第9节 拨开云雾见月明 40 第10节 逻辑挑战1:交换小房子中的数 42 第11节 天啊!这怎么能看懂 45 等等。。。。。。。。。。。。。。。

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧