树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree

 1 // 树形DP CCPC网络赛  HDU5834 Magic boy Bi Luo with his excited tree
 2 // 题意:n个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以走多次,问从每个点出发的最大获益
 3 // 思路:
 4 // dp[i]: 从i点出发回到i点的最大值
 5 // d[i][0] 从i点出发不回来的最大值
 6 // d[i][1] 从i点出发取最大值的下一个点
 7 // d[i][2] 从i点出发取次大值
 8 // dfs1处理出这四个
 9 // 然后,从1开始转移,分别DP求子节点从父亲转移过来的最大值,和从父亲出去不回来的最大值
10 
11 #include <bits/stdc++.h>
12 using namespace std;
13 #define LL long long
14 const double inf = 123456789012345.0;
15 const LL MOD =100000000LL;
16 const int N =1e5+10;;
17 #define clc(a,b) memset(a,b,sizeof(a))
18 const double eps = 1e-7;
19 void fre() {freopen("in.txt","r",stdin);}
20 void freout() {freopen("out.txt","w",stdout);}
21 inline int read() {int x=0,f=1;char ch=getchar();while(ch>'9'||ch<'0') {if(ch=='-') f=-1; ch=getchar();}while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}return x*f;}
22 
23 vector<pair<int,int> > g[N];
24 int a[N],ans[N];
25 int dp[N],d[N][3];
26 void dfs1(int u,int f){
27     dp[u]=a[u];
28     for(int i=0;i<(int)g[u].size();i++){
29        int v=g[u][i].first;
30        int val=g[u][i].second;
31        if(v==f) continue;
32        dfs1(v,u);
33        dp[u]+=max(0,dp[v]-2*val);
34     } 
35     d[u][0]=d[u][2]=a[u];
36     d[u][1]=-1;
37     for(int i=0;i<(int)g[u].size();i++){
38         int v=g[u][i].first;
39         int val=g[u][i].second;
40         if(v==f) continue;
41         int tem=dp[u]-max(0,dp[v]-2*val)+max(0,d[v][0]-val);//当前选择路径不回来的最大值
42         if(tem>d[u][0]){
43             d[u][2]=d[u][0];
44             d[u][0]=tem;
45             d[u][1]=i;
46         }
47         else if(tem>d[u][2]){
48             d[u][2]=tem;
49         }
50     }
51 }
52 
53 //no从父亲不回来的最大值,yes从父亲回来的最大值
54 void dfs2(int u,int f,int no,int yes){
55     ans[u]=max(dp[u]+no,yes+d[u][0]);
56     for(int i=0;i<(int)g[u].size();i++){
57         int v=g[u][i].first;
58         int val=g[u][i].second;
59         if(v==f) continue;
60         int tem1,tem2;
61         if(i==d[u][1]) tem1=max(0,d[u][2]-max(0,dp[v]-2*val));//从父亲出去但不是最优方案的最大值
62         else tem1=max(0,d[u][0]-max(0,dp[v]-2*val));
63         tem2=max(0,dp[u]-max(0,dp[v]-2*val));//从父亲出去又回来的最大值
64         tem1=max(0,max(tem1+yes-val,tem2+no-val));//儿子节点从父亲转移过来的是 max(父亲儿子节点出去不回来+父亲的父亲出去回来的最大值,父亲儿子节点出去回来+父亲的父亲出去不回来的最大值)
65         tem2=max(0,yes+tem2-2*val);
66         dfs2(v,u,tem1,tem2);
67     }
68 }
69 
70 int main(){
71     int T;
72     scanf("%d",&T);
73     for(int cas=1;cas<=T;cas++){
74         int n;
75         scanf("%d",&n);
76         for(int i=1;i<=n;i++) g[i].clear();
77         for(int i=1;i<=n;i++) scanf("%d",&a[i]);
78         for(int i=1;i<n;i++){
79             int u,v,x;
80             scanf("%d%d%d",&u,&v,&x);
81             g[u].push_back(make_pair(v,x));
82             g[v].push_back(make_pair(u,x));
83         }
84         dfs1(1,-1);
85         dfs2(1,-1,0,0);
86         printf("Case #%d:
",cas);
87         for(int i=1;i<=n;i++) printf("%d
",ans[i]);
88     }
89     return 0;
90 }
原文地址:https://www.cnblogs.com/ITUPC/p/5782004.html