题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4044
题意:一个树上的塔防游戏。给你n个结点的树,你要在树结点上建塔防御,在第 i 个结点上有 ki 种防御塔可供选择,每个塔给你建塔花费 pricei 和塔能造成的伤害 poweri (可以认为每个塔只能攻击一次),现在有一个怪物从结点1出发,随意的沿着树边去叶子结点,问你最坏的情况最大能对怪物造成多少伤害(即假设怪物会沿着受伤最小的路径走),开始有 m 单位钱
2<=n<=1000, 0<=ki<=50, 0<=pricei<=200, 0<=poweri<=5e4, 0<=m<=200
题解:树形dp,f[u][x]表示在以 u 为根的子树上花费 x 最多造成 f[u][x] 的伤害
考虑状态转移,对于当前结点u他有儿子 v1,v2,,,,vt,你现在有 x 单位钱,如何给这 t 个儿子分配使得伤害最小的儿子伤害最高?
依次遍历儿子,用maxSon[y]表示给到当前儿子为止总共花 y 单位钱,获得的最大收益
时间复杂度:O(n*m^2)
1 /* 2 * Problem: 3 * Author: SHJWUDP 4 * Created Time: 2015/10/6 星期二 22:57:51 5 * File Name: 1001.cpp 6 * State: 7 * Memo: 8 */ 9 #include <iostream> 10 #include <cstdio> 11 #include <vector> 12 #include <cstring> 13 #include <algorithm> 14 15 using namespace std; 16 17 const int INF=0x7f7f7f7f; 18 19 struct Graph { 20 struct Edge { 21 int u, v; 22 }; 23 int n, m; 24 vector<Edge> edges; 25 vector<vector<int>> G; 26 vector<vector<pair<int,int>>> tower; 27 vector<vector<int>> f; 28 Graph(int _n):n(_n),m(0),G(_n),tower(n),f(n){} 29 void addEdge(int u, int v) { 30 edges.push_back({u, v}); 31 m=edges.size(); 32 G[u].push_back(m-1); 33 } 34 vector<int> & operator[](int x) { 35 return G[x]; 36 } 37 }; 38 39 int n, m; 40 void dfs(Graph & G, int u, int fa) { 41 auto & tower=G.tower[u]; 42 auto & bag=G.f[u]; 43 bag.assign(m+1, 0); 44 for(const auto & p : tower) { 45 if(p.first>m) continue; 46 bag[p.first]=max(bag[p.first], p.second); 47 } 48 if(G[u].size()==1 && u!=0) return; 49 vector<int> maxSon(m+1, INF); 50 for(auto i : G[u]) { 51 const auto & e=G.edges[i]; 52 if(e.v==fa) continue; 53 dfs(G, e.v, u); 54 const auto & vbag=G.f[e.v]; 55 for(int j=m; j>=0; --j) { 56 int mx=0; 57 for(int k=0; k<=j; ++k) { 58 mx=max(mx, min(maxSon[j-k], vbag[k])); 59 } 60 maxSon[j]=mx; 61 } 62 } 63 for(int v=m; v>=0; --v) { 64 for(int i=0; i<=v; ++i) { 65 if(maxSon[i]==INF) continue; 66 bag[v]=max(bag[v], bag[v-i]+maxSon[i]); 67 } 68 } 69 } 70 int main() { 71 #ifndef ONLINE_JUDGE 72 freopen("in", "r", stdin); 73 //freopen("out", "w", stdout); 74 #endif 75 int T; 76 scanf("%d", &T); 77 while(T--) { 78 scanf("%d", &n); 79 Graph tree(n); 80 for(int i=0; i<n-1; ++i) { 81 int a, b; 82 scanf("%d%d", &a, &b); 83 --a; --b; 84 tree.addEdge(a, b); 85 tree.addEdge(b, a); 86 } 87 scanf("%d", &m); 88 for(int i=0; i<n; ++i) { 89 int num; 90 scanf("%d", &num); 91 tree.tower[i].resize(num); 92 for(auto & p : tree.tower[i]) { 93 scanf("%d%d", &p.first, &p.second); 94 } 95 } 96 dfs(tree, 0, -1); 97 int ans=0; 98 for(auto x : tree.f[0]) ans=max(ans, x); 99 printf("%d\n", ans); 100 } 101 return 0; 102 }