题意
某厂采用一种奇怪的方式发奖金,给出一个上下级关系树,大BOSS是1号根节点,别的员工都有自己的上司。对于每个员工,它有三种选择,要么接受上级下发的奖金,要么给所有下级发奖金,要么啥都不做(只有傻子才会这样,所以你可以当成没这种选择),大BOSS一定发奖金。只要一个员工选择收奖金,他就得到1000块。
现在要你设计一种方案,使得所有人收到的奖金的总数额最大。
思路
树DP解法
对于每一个节点,都有两种状态:选择收奖金,选择收奖金。
对于选择收奖金的节点的儿子节点,一定不可以选择收奖金。
对于选择发奖金的节点的儿子节点,可以选择收他的奖金,也可以选择发奖金。
这样就可以建立dp数组dp[a][0/1],a是节点对应的编号,0/1表示该节点选择收/发奖金的状态。利用DFS下潜到叶子节点之后,就可以开始树DP了。
状态转移的方程可以参考dfs()方法。
输出路径的话,只要记录下每一次的决策,DP结束之后反查就可以搞定。
贪心解法
引用自JHC23的Blog。
自底而顶遍历,如果自己的上级没有接受奖金(那么就能够把钱给发自己了),而自己也从不增接受奖金则可以获得奖金,同时标记自己和上级。这样下去就可以得到可得到最大奖金。
代码
树DP解法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
// // SGU195.cpp // playground // // Created by Adam Chang on 2015/07/29. // Copyright © 2015年 Adam Chang. All rights reserved. // #include <iostream> #include <algorithm> #include <queue> #include <vector> #include <cstdlib> #include <cstdio> #include <string> #include <cstring> #include <ctime> #include <iomanip> #include <cmath> #include <set> #include <stack> #include <cmath> #include <map> using namespace std; struct nodeType{ vector<int> to; int select; } vertex[500005]; void addEdge(int from,int to){ vertex[from].to.push_back(to); } int dp[500005][2]; void dfs(int cur){ nodeType &currNode = vertex[cur]; for (int i = 0; i < currNode.to.size(); i++) { dfs(currNode.to[i]); } for (int i = 0; i < currNode.to.size(); i++) { if (dp[cur][0]+dp[currNode.to[i]][0]+1>= max(dp[cur][1]+dp[currNode.to[i]][1],dp[cur][1]+dp[currNode.to[i]][0])) { currNode.select = currNode.to[i]; } dp[cur][1] = max(dp[cur][0]+dp[currNode.to[i]][0]+1, max(dp[cur][1]+dp[currNode.to[i]][1],dp[cur][1]+dp[currNode.to[i]][0])); dp[cur][0] = max(dp[cur][0]+dp[currNode.to[i]][1],dp[cur][0]+dp[currNode.to[i]][0]); } } vector<int> ans; void dfs_getans(int cur){ nodeType &currNode = vertex[cur]; if (dp[cur][0] >= dp[cur][1]) { for (int i = 0; i < currNode.to.size(); i++) { dfs_getans(currNode.to[i]); } }else{ if (currNode.select) { ans.push_back(currNode.select); } for (int i = 0; i < currNode.to.size(); i++) { dfs_getans(currNode.to[i]); } } } int main(){ int n = 0; scanf(" %d",&n); for (int i = 1; i <= n; i++) { vertex[i].to.clear(); vertex[i].select = 0; dp[i][0] = dp[i][1] = 0; } ans.clear(); for (int i = 2; i <= n; i++) { int boss = 0; scanf(" %d",&boss); addEdge(boss,i); } dfs(1); dfs_getans(1); sort(ans.begin(), ans.end()); cerr << dp[1][0] << " " << dp[1][1] << endl; printf("%d\n",(int)ans.size()*1000); if (ans.size()) { for (int i = 0; i < (int)ans.size()-1; i++) { printf("%d ",ans[i]); } printf("%d\n",ans[ans.size()-1]); } return 0; } |