题目链接:https://hihocoder.com/problemset/problem/1199。
题意:一棵以1为根的树,每个点有一个p值和q值,到这个点需要当前分数大于等于p,然后消耗掉(p-q)的分数。问一种遍历方式,使得一开始在1所需的分数最小并能够遍历完所有的点。
分析见代码:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 #include <vector> 5 using namespace std; 6 const int N = 100000 + 100; 7 8 // https://hihocoder.com/contest/hiho109/problem/1 9 int n; 10 int a[N],b[N]; 11 vector<int> G[N]; 12 13 bool cmp(int x,int y) {return b[x] > b[y];} 14 15 int dfs(int u,int fa) 16 { 17 vector<int> child; 18 for(int i=0;i<G[u].size();i++) 19 { 20 int v = G[u][i]; 21 if(v == fa) continue; 22 dfs(v, u); 23 child.push_back(v); 24 } 25 // 先找能返还最多分数的点,这个贪心策略还是挺有道理的 26 sort(child.begin(), child.end(), cmp); 27 int &m = a[u]; 28 int cost = a[u] - b[u]; 29 for(int i=0;i<child.size();i++) 30 { 31 int v = child[i]; 32 // cost表示先去访问前面的点,然后再来访问v时需要花费的分数 33 if(a[v] + cost > m) m = a[v] + cost; 34 cost += a[v] - b[v]; 35 } 36 // b在这里可以表示返还的钱,自然可以等于u点最少需要的分数,减去花费cost. 37 b[u] = m - cost; 38 } 39 40 int main() 41 { 42 while(scanf("%d",&n) == 1 && n) 43 { 44 for(int i=1;i<=n;i++) {scanf("%d%d",a+i,b+i);G[i].clear();} 45 for(int i=1;i<n;i++) 46 { 47 int u,v;scanf("%d%d",&u,&v); 48 G[u].push_back(v); 49 G[v].push_back(u); 50 } 51 dfs(1,-1); 52 printf("%d\n",a[1]); 53 } 54 return 0; 55 }