牛客网:牛牛打怪兽

链接:https://ac.nowcoder.com/acm/contest/6630/B
来源:牛客网

题目描述
题意
身为屯里第一剑士的牛牛来到训练场里闯关,由于过于勤奋,牛牛的宝剑的耐久度降到了 22 ,这意味着牛牛最多只能打倒两只怪兽,否则将会被淘汰。

训练场的地图可以看作一棵以 11 为根节点的树,训练场的终点为这棵树的叶子结点,树上的每个结点最多有一只怪兽,结点与结点间的边上没有怪兽。

每一个有怪兽的结点上牛牛都需要打倒怪兽才算安全,并且牛牛一旦选定好打怪路线之后便不能走回头路。

请问牛牛有多少种到达终点且不被淘汰的路径。

输入
第一个参数为 nn ,(1\leq n\leq 100,000)(1≤n≤100,000)

第二个参数为大小为 n-1n−1 的点对 (u_i, v_i)(u i,v i) 的集合,其中 (u_i, v_i)(u i,v i) 表示结点 u_iui与结点 v_ivi 之间有一条边,1<= u_i, v_i <= n1≤u i ,v i≤n
第三个参数为大小为 n 的 0/1 序列 f ,若 f_if
i 为 00 表示i-1结点没有怪兽,否则表示 i-1 结点有怪兽。

返回
一个整数,表示牛牛能到达终点且不被淘汰的路径数。

示例1
输入
复制

7,[(7,2),(6,1),(5,2),(1,2),(4,6),(6,3)],[0,0,1,0,1,0,0]

输出

4

说明

样例中的四条路径分别为: (1 - 2 - 7), (1 - 2 - 5) , (1 - 6 - 3), (1 - 6 - 4)

牛客网:牛牛打怪兽_第1张图片

思路:树的深度优先遍历
这道题的思路没什么难度,难点在于给出的是点对的集合,需要从点对中构建出二叉树。我们可以将二叉树看作一种特殊的图,因为根节点确定,那么根据所有的边构建出一个邻接表,从根节点出发进行深度优先搜索,即可以搜索到所有的节点。而需要注意的是,在构建邻接表的时候,会将父子的关系两次加入到邻接表中,遍历的时候需要进行特别的判断。
注:
1. 全局开数组可以减少参数的传递;
2. 在进行树的邻接表遍历的时候,和图的深度优先搜索没有差别,主要在向下进行搜索的时候需要传入当前的节点,因为子节点中也存有指向父节点的边,需要进行剔除;
3. 这种情况下进行叶子节点的判断,有两种方式,一种是使用一个变量记录向下dfs的数量,即子节点的数量,为0的时候说明是叶子节;另一种是,当前节点邻接表的大小为1的时候,说明是叶子节点(除非是root)。

/**
 * struct Point {
 *	int x;
 *	int y;
 * };
 */

class Solution {
public:
    /**
     * 返回牛牛能到达终点且不被淘汰的路径数
     * @param n int整型 
     * @param Edge Point类vector 
     * @param f int整型vector 
     * @return int整型
     */
    vector<int> a[100100];
    int count;
    
    int solve(int n, vector<Point>& Edge, vector<int>& f) {
        // write code here
        for(auto v:Edge)
        {
            a[v.x].push_back(v.y);
            a[v.y].push_back(v.x);
        }
        count = 0;
        
        dfs(1,0,f,0);
        return count;
    }
    
    void dfs(int cur,int father,vector<int> &f,int monster)
    {
        if(f[cur-1])monster++;
        if(monster>2)return ;
        int son = 0;
        for(auto node:a[cur])
        {
            if(node==father)continue;
            son++;
            dfs(node,cur,f,monster);
        }
        if(son==0)count++;
    }
};

你可能感兴趣的:(leetcode)