链接: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. 全局开数组可以减少参数的传递;
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++;
}
};