Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 3862 | Accepted: 2171 |
Description
Input
Output
Sample Input
7 1 1 1 1 1 1 1 1 3 2 3 6 4 7 4 4 5 3 5 0 0
Sample Output
5
【题意】
公司有n个人,每个人有价值vi,有一天举办年会,每个人都可以参加,但有严格的等级制度,参加活动时,不能同时出现a和a的上司,问如何才能使总和最大。
【分析】
每个人只有去和不去两种状态,设DP[i][0]和DP[i][1]分别表示第i个人不参加和参加年会,获得的总的最大价值。
则状态转移方程为:
DP[i][1] += DP[j][0],
DP[i][0] += max{DP[j][0],DP[j][1]};其中j为i的孩子节点。
这样,从根节点r进行dfs,最后结果为max{DP[r][0],DP[r][1]}。
(分析来自yzmduncan)
第2~n+1行为这n个人的价值
代码:
1 #include "stdio.h" //简单的树形dp题 2 #include "string.h" 3 #include "queue" 4 using namespace std; 5 6 #define N 60005 7 #define INF 0x3fffffff 8 9 struct node 10 { 11 int x,y; 12 int weight; 13 int next; 14 }edge[4*N]; 15 int idx,head[N]; 16 17 int root; 18 int du[N]; 19 int value[N]; 20 21 int dp[N][2]; 22 int MAX(int a,int b) { return a>b?a:b; } 23 24 void Init() 25 { 26 idx = 0; 27 memset(head,-1,sizeof(head)); 28 } 29 30 void Add(int x,int y,int weight) 31 { 32 edge[idx].x = x; 33 edge[idx].y = y; 34 edge[idx].weight = weight; 35 edge[idx].next = head[x]; 36 head[x] = idx++; 37 } 38 39 void DFS(int i) // 40 { 41 int k,j; 42 dp[i][0] = 0; 43 dp[i][1] = value[i]; 44 for(k=head[i]; k!=-1; k=edge[k].next) 45 { 46 j = edge[k].y; 47 DFS(j); 48 dp[i][0] += MAX(dp[j][0],dp[j][1]); 49 dp[i][1] += dp[j][0]; 50 } 51 } 52 53 54 int main() 55 { 56 int n; 57 int i; 58 int x,y; 59 while(scanf("%d",&n)!=EOF) 60 { 61 Init(); 62 memset(du,0,sizeof(du)); //记录节点的入度 63 memset(dp,0,sizeof(dp)); 64 for(i=1; i<=n; ++i) 65 scanf("%d",&value[i]); 66 while(scanf("%d %d",&x,&y) && x+y>0) 67 { 68 Add(y,x,0); 69 du[x]++; 70 } 71 for(i=1; i<=n; ++i) 72 { 73 if(du[i]==0) 74 root = i; 75 } 76 DFS(root); 77 printf("%d\n",MAX(dp[root][0],dp[root][1])); 78 } 79 return 0; 80 }