题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1520
题目:
题意:一个学校要办校庆,校长决定邀请员工参加,但是下属和他的直系同时参加的话,下属将会无法开心的玩(每个人都有一个开心值),问怎样邀请才能使得总的开心值最大。(关系图为树形)
思路:树形dp,每个人都有邀请和不邀请两种状态。加入邀请了当前这个人,那么就不能邀请他的下属;如果不邀请当前这个人,那么既可以邀请他的下属,也可以不邀请他的下属,为了让总的开心值最大,取他的下属两种情况下子树开心值的最大值。我们用dp[i][j]来记录以这个点为根节点得子树的最大开心值,dp[i][0]表示不邀请当前节点,dp[i][1]表示邀请当前节点。由刚刚的分析我们得知:dp[i][1]+=dp[j][0],dp[i][0]+=max(dp[j][0],dp[j][1]),其中j为i的子节点,最后答案就是max(dp[s][1],dp[s][0]),其中s是根节点,由题意知本题根节点为1。树形dp一般都是用dfs来进行处理,而信息的传递有从子节点传向父亲节点和从父亲节点到子节点两种情况,而本题显然是选择第一种信息传递方式。
代码实现如下:
1 #include <set> 2 #include <map> 3 #include <queue> 4 #include <stack> 5 #include <cmath> 6 #include <bitset> 7 #include <cstdio> 8 #include <string> 9 #include <vector> 10 #include <cstdlib> 11 #include <cstring> 12 #include <iostream> 13 #include <algorithm> 14 using namespace std; 15 16 typedef long long ll; 17 typedef unsigned long long ull; 18 19 #define bug printf("********* "); 20 #define FIN freopen("in.txt", "r", stdin); 21 #define debug(x) cout<<"["<<x<<"]" <<endl; 22 #define IO ios::sync_with_stdio(false),cin.tie(0); 23 24 const int mod = 1e9 + 7; 25 const int maxn = 6e3 + 7; 26 const double pi = acos(-1); 27 const int inf = 0x3f3f3f3f; 28 const ll INF = 0x3f3f3f3f3f3f3f3f; 29 30 int n, s, u, v; 31 int dp[maxn][2], in[maxn]; 32 vector<int> G[maxn]; 33 34 void dfs(int u) { 35 int v; 36 for(int i = 0; i < G[u].size(); i++) { 37 v = G[u][i]; 38 dfs(v); 39 dp[u][1] += dp[v][0]; 40 dp[u][0] += max(dp[v][1], dp[v][0]); 41 } 42 } 43 44 int main() { 45 //FIN; 46 while(~scanf("%d", &n)) { 47 memset(in, 0, sizeof(in)); 48 for(int i = 1; i <= n; i++) { 49 scanf("%d", &dp[i][1]); 50 dp[i][0] = 0; 51 G[i].clear(); 52 } 53 while(~scanf("%d%d", &u, &v) && u && v) { 54 G[v].push_back(u); 55 in[u]++; 56 } 57 for(int i = 1; i <= n; i++) { 58 if(in[i] == 0) { 59 s = i; 60 break; 61 } 62 } 63 dfs(s); 64 printf("%d ", max(dp[s][1], dp[s][0])); 65 } 66 return 0; 67 }