题意:给定一棵树,每个叶子有一个权值,每条边也有一个权值,现在让你删最少的结点,使得从任何结点出发到另一个结点的边上权值和都小于两个结点的权值。
析:很明显是DFS,不过要想找出最少的结点可能不太容易,所以我们可以先找出剩下结点最多,那么用总数减去这个就好,那么怎么找哪些结点是剩下的呢?首先要知道,如果一个结点要被删掉,
那么它的子树肯定也要被删掉,并且,要满足dist(v, u) <= a[u]才是可能留下的,那么只要dist(v, u) >a[u],就不要,所以一定要注意的是,结点的距离可能为负,所以要在DFS时判断一下,肯定是取非负的,
想一想为什么。
代码如下:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 5; typedef long long LL; typedef pair<int, int> P; int a[maxn]; vector<P> G[maxn]; int ans; void dfs(int u, LL d, int fa){ if(a[u] < d) return ;//不满足要删掉 ++ans;//计算最多有多少结点 for(int i = 0; i < G[u].size(); ++i) if(G[u][i].first == fa) continue;//不能返回父结点 else dfs(G[u][i].first, max(0LL, d+G[u][i].second), u);//判断是不是大于等于0 } int main(){ int n, p, c; cin >> n; for(int i = 1; i <= n; ++i) cin >> a[i]; for(int i = 1; i < n; ++i){ cin >> p >> c; G[i+1].push_back(P(p, c)); G[p].push_back(P(i+1, c)); } ans = 0; dfs(1, 0, -1); printf("%d\n", n - ans); return 0; }