考虑二进制树,如:
将节点视为开关,最初为OFF
,节点之间的边缘为管灯(最初不发光)。当我们打开特定节点时,连接到该节点的所有边(管灯)都会发光。找到需要转动ON
的最小数量的开关,以使整个二进制树发光。
例如,如果我打开2,3,4 and 9
或2,3,8,9
,则所有管灯都会亮起。所以答案是4
[见图]
我在接受采访时被问及这个问题。任何人都可以帮我算法/伪代码吗?无需工作代码。
对于程序员和程序员,请认为输入如下:
n
:给定的边数
然后n
行以x y
形式显示,其中x
和y
是边缘的两个端点。
根据上图,输入将是:
10
1 2
1 3
2 5
...
到目前为止,我已经找到了一些案例:我永远不需要照亮叶子节点
基于上述事实,是否存在简单的递归解决方案?
编辑:如果只给出Root
树的input
,算法是否会更改[假设树被表示为链表] ??
答案 0 :(得分:3)
这是树上的最小顶点覆盖问题(MVC)。你可以用两种方式解决它:
树是一个二分图,MVC问题相当于找到一个可以求解的多项式时间的最大匹配。
通过贪婪算法进行如下操作。任意植树。选择连接到叶子的所有顶点并将它们放在最终的集合中(打开它们)。 (这些顶点或叶子应该在最终解决方案中)。删除这些顶点和所有边,并保持顶点连接到它们,并在图的其余部分上使用相同的算法。
以下是该算法工作原理的证明: 假设输入是一个大小为&n的森林。显然,应该打开一个叶子或它的邻居(除了没有连接它的边缘)。所以第一步是正确的。
一旦我们删除了所有叶子和所有叶子的父母,剩下的图形就会出现在森林中的“森林”上。顶点,其中t是原始图形中叶子及其父级的数量。假设我们知道什么是开始时的离开节点。我们执行以下操作来解决O(n)
中的问题:
如果我们知道删除那些' t'之后的叶子是什么?然后我们在T(n) = O(t) + T(n-t)
中解决问题,其结果为T(n) = O(n)
。为了在删除那些t
顶点后找到新的叶子,我们创建一个新的叶子列表。每次我们删除这些t
顶点中的任何一个时,我们检查它们是否有一个没有连接到原始叶子的一级邻居,我们将该顶点添加到新的假期列表中。在我们完成删除叶子及其邻居的过程后,我们使用新的叶子列表更新原始叶子列表。因此,在每个步骤中,我们都有叶子列表,因此可以在O(n)
中完成。
答案 1 :(得分:0)
您可以通过考虑每个子树需要打开的最小开关数来递归地解决它,假设根节点已打开并且还假设它已关闭。
如果根节点已打开,则子节点可以打开或关闭,因此minSwitchesAssumingRootOn
递归调用minSwitches
。如果根节点已关闭,则子节点必须处于打开状态,以使连接到根节点的边缘处于打开状态,因此minSwitchesAssumingRootOff
将递归调用minSwitchesAssumingRootOn
。
可以使用备忘录存储子总数以加快速度。 tree.minAssumingOff
和tree.minAssumingOn
应初始化为-1。
的伪代码:
int minSwitches(tree)
{
if(tree == null)
return 0;
return min(minSwitchesAssumingRootOff(tree),
minSwitchesAssumingRootOn(tree));
}
int minSwitchesAssumingRootOn(tree)
{
if(tree == null)
return 0;
if(tree.minAssumingOn == -1)
tree.minAssumingOn = 1 + minSwitches(tree.left) + minSwitches(tree.right);
return tree.minAssumingOn;
}
int minSwitchesAssumingRootOff(tree)
{
if(tree == null)
return 0;
if(tree.minAssumingOff == -1)
tree.minAssumingOff = minSwitchesAssumingRootOn(tree.left) +
minSwitchesAssumingRootOn(tree.right);
return tree.minAssumingOff;
}
答案 2 :(得分:0)
这个问题和leetcode上的这个问题很相似https://leetcode.com/problems/binary-tree-cameras/ 我的解决方案
// -1 -> need cam
// 0 -> has cam
// 1 -> covered by child
int cam;
class Solution {
public:
int solve(TreeNode* root){
if(root==NULL){
return 1;
}
int l = solve(root->left);
int r = solve(root->right);
if(l==-1 || r==-1){ //if any child node node need a cam this node must have a cam
cam++;
return 0;
}
if(l==0 || r==0){ //if any child node has cam this node doesn't need a cam its covered by child
return 1;
}
return -1; //else its need a cam
}
int minCameraCover(TreeNode* root){
cam=0;
if(solve(root)==-1){ //if root need a cam
cam++;
}
return cam;
}
};