标签:
题目链接:传送门
题目大意:给你一棵树,根节点为1,树上每一个节点都有一个花费值和收入值(花费值>=收入值),要访问一个节点需先支付花费值,访问该节点结束后得到收入值
同时访问树时要求是有序的,即访问一个节点后,需要访问完它所有的子节点,才能访问它的兄弟节点。问我们最少需要带多少钱就能访问完所有的节点。
题目思路:感觉是一道比较有趣的题,首先我们可以由题意知,访问完整个树付出的代价是一定的(总花费-总收入),设代价为 X,访问完后我们会得到总收入 Y,
由题意可知访问完后我们手上的钱数 Y>=0,我们带的钱要尽可能少,那么Y就要尽可能小,我们要把每个节点返回的钱尽可能花出去,而不是留在手上。
那么只需要dfs一遍,处理子节点的访问顺序,返回每个节点访问完后得到的最优情况(对每个节点都按带钱最少考虑)。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <cstring> #include <stack> #include <cctype> #include <queue> #include <string> #include <vector> #include<functional> #include <set> #include <map> #include <climits> #define lson root<<1,l,mid #define rson root<<1|1,mid+1,r #define fi first #define se second #define ping(x,y) ((x-y)*(x-y)) #define mst(x,y) memset(x,y,sizeof(x)) #define mcp(x,y) memcpy(x,y,sizeof(y)) using namespace std; #define gamma 0.5772156649015328606065120 #define MOD 1000000007 #define inf 0x3f3f3f3f #define N 100005 #define maxn 10005 typedef pair<int,int> PII; typedef long long LL; int n,m; int a[10005],b[10005]; vector<int>V[10005]; struct Node{ int x,v; ///x花费值,v收入值 bool operator<(const Node&a)const{ return v>a.v; } }; Node dfs1(int x,int fa){ Node t1; vector<Node>v; for(int u:V[x]){ if(u==fa)continue; t1=dfs1(u,x); v.push_back(t1); } sort(v.begin(),v.end()); ///按收入从大到小排序 int temp1=a[x],temp2=b[x]; ///temp1花费,temp2收入,要访问当前节点需要花费a[x],访问当前节点后收入b[x] for(Node u:v){ temp2-=u.x; if(temp2<0){ ///如果当前收入不够支付下一个节点的花费,则需要多带钱 temp1-=temp2; temp2=0; } temp2+=u.v; } t1.x=temp1;t1.v=temp2; return t1; } int main() { int i,j,group,x,y,Case=0; while(scanf("%d",&n)!=EOF){ for(i=1;i<=n;++i) scanf("%d%d",&a[i],&b[i]); for(i=1;i<n;++i){ scanf("%d%d",&x,&y); V[x].push_back(y); V[y].push_back(x); } Node node=dfs1(1,-1); printf("%d\n",node.x); } return 0; }
hiho一下第109周《Tower Defense Game》
标签:
原文地址:http://www.cnblogs.com/Kurokey/p/5730508.html