找到要打开以照亮二叉树的最小开关数

时间:2016-10-19 09:05:13

标签: algorithm

考虑二进制树,如:

enter image description here

将节点视为开关,最初为OFF,节点之间的边缘为管灯(最初不发光)。当我们打开特定节点时,连接到该节点的所有边(管灯)都会发光。找到需要转动ON的最小数量的开关,以使整个二进制树发光。

例如,如果我打开2,3,4 and 92,3,8,9,则所有管灯都会亮起。所以答案是4 [见图]

我在接受采访时被问及这个问题。任何人都可以帮我算法/伪代码吗?无需工作代码。

对于程序员和程序员,请认为输入如下:

n:给定的边数

然后n行以x y形式显示,其中xy是边缘的两个端点。

根据上图,输入将是:

10
1 2
1 3
2 5
...

到目前为止,我已经找到了一些案例:我永远不需要照亮叶子节点

基于上述事实,是否存在简单的递归解决方案?

编辑:如果只给出Root树的input,算法是否会更改[假设树被表示为链表] ??

3 个答案:

答案 0 :(得分:3)

这是树上的最小顶点覆盖问题(MVC)。你可以用两种方式解决它:

  1. 树是一个二分图,MVC问题相当于找到一个可以求解的多项式时间的最大匹配。

  2. 通过贪婪算法进行如下操作。任意植树。选择连接到叶子的所有顶点并将它们放在最终的集合中(打开它们)。 (这些顶点或叶子应该在最终解决方案中)。删除这些顶点和所有边,并保持顶点连接到它们,并在图的其余部分上使用相同的算法。

  3. 以下是该算法工作原理的证明: 假设输入是一个大小为&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.minAssumingOfftree.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;
    }
};