假设 1 为 根节点
dp[i][0] 代表从自己出发选择到儿子节点最后必须返回自己的最大价值
dp[i][1] 代表从自己出发选择到儿子节点最后可选择不回来的最大价值 并记录最后选择的离开节点 id[i]
树形dp先跑一遍出来
再第二遍 dfs 因为每个节点也可以流向父节点所以要合并
玛德太弱了超级复杂啊!!!!!!!!!!!!!!
分两种情况
一种是这个点正好是父节点的id,也就是父节点选择的最佳出走方案点 这样合并的时候这个点因为要换它选择父节点了,所以这个点要抛弃重新选择父节点的最佳出走方案总不能来来回回的走。。。
另一种就是直接合并了 把父节点的dp[fa][0] 减去 这个节点流向父节点的最优值再减去两条边的价值就是父节点流向它的了,dp[fa][1]一个意思
#include<cstdio> #include<algorithm> #include<iostream> #define maxn 110005 using namespace std; int dp[maxn][3],ans[maxn],va[maxn]; int cost[2*maxn],Next[2*maxn],last[2*maxn],e[2*maxn],l,n,id[maxn]; void add(int a,int b,int C) { e[l] = b; cost[l] = C; Next[l] = last[a]; last[a] = l; l++; } void dfs1(int pre,int fa) { dp[pre][0] = va[pre]; dp[pre][1] = va[pre]; id[pre] = -1; for(int i = last[pre]; i!=-1; i = Next[i]) { int v = e[i]; if(v == fa)continue; dfs1(v,pre); int tem = max(0,dp[v][0] - 2 * cost[i]); int tem2 = max(0,dp[v][1] - cost[i]); dp[pre][1] = dp[pre][1] +tem; if(dp[pre][0] + tem2 > dp[pre][1]) { dp[pre][1] = dp[pre][0] + tem2; id[pre] = v; } dp[pre][0] += tem; } } void dfs2(int pre,int fa,int sum1,int sum2) { int sum11 = dp[pre][0]; int sum22 = dp[pre][1]; ans[pre] = max(sum2 + sum11,sum1 + sum22); sum22 += sum1; if(sum11 + sum2 > sum22) { sum22 = sum11 + sum2; id[pre] = fa; } sum11 += sum1; for(int i = last[pre]; i!=-1; i = Next[i]) { int v = e[i]; if(v == fa)continue ; if(v == id[pre]) { int sum11 = sum1 + va[pre],sum22 = sum2 + va[pre]; for(int j = last[pre]; j != -1 ;j = Next[j]) { int vv = e[j]; if(vv == v || vv == fa)continue ; int temp = max(0,dp[vv][0] - cost[j]*2); sum22 = max(sum11 + max(0,dp[vv][1] - cost[j]),sum22 + temp); sum11 += temp; } sum11 = max(0,sum11 - 2*cost[i]); sum22 = max(0,sum22 - cost[i]); dfs2(v,pre,sum11,sum22); } else{ int temp1 = max(0,dp[v][0] - 2 * cost[i]); int temp2 = max(0,sum11 - temp1 - 2 * cost[i]); int temp3 = max(0,sum22 - temp1 - cost[i]); dfs2(v,temp2,temp3); } } } int main() { int t,i1 = 1; scanf("%d",&t); while(t--) { scanf("%d",&n); for(int i = 0; i <=n; i++) last[i] = -1; l = 0; for(int i = 1; i <= n; i++) scanf("%d",&va[i]); for(int i=1;i<n;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,c); add(b,a,c); } dfs1(1,-1); dfs2(1,-1,0,0); printf("Case #%d:\n",i1); i1++; for(int i = 1; i <= n; i++) printf("%d\n",ans[i]); } return 0; }