标签:树形dp
5 1 1 2 1 3 1 1 1
3 2 3 4 4题意:给一棵树,每条树边都有权值,问从每个顶点出发,经过的路径权值之和最大为多少?每条树边都只能走一次。分析:以每个结点为根找到最长的子节点链,加上该结点为孩子的另一支子树链。详细解析#include <iostream> #include <cstdio> #include <cstring> #include <stack> #include <queue> #include <map> #include <set> #include <vector> #include <cmath> #include <algorithm> using namespace std; const double eps = 1e-6; const double pi = acos(-1.0); const int INF = 0x3f3f3f3f; const int MOD = 1000000007; #define ll long long #define CL(a,b) memset(a,b,sizeof(a)) #define MAXN 10005 struct node { int v,len,sum; node *next; }tree[MAXN*2], *head[MAXN*2]; int n,ptr,vis[MAXN]; int dp[MAXN]; void init() { ptr=1; CL(vis, 0); CL(dp, 0); CL(head, NULL); } void add(int s, int e, int len)//建树 { tree[ptr].v = e; tree[ptr].len = len; tree[ptr].next = head[s];head[s] = &tree[ptr++]; tree[ptr].v = s; tree[ptr].len = len; tree[ptr].next = head[e],head[e] = &tree[ptr++]; } void dfs1(int idx)//以idx为根的最长链 { vis[idx] = 1; node *p = head[idx]; while(p != NULL) { if(!vis[p->v]) { dfs1(p->v); dp[idx] = max(dp[idx], dp[p->v]+p->len); p->sum = dp[p->v]+p->len; } p = p->next; } } void dfs2(int father, int child)//同根的另一支子树 { if(vis[child]) return ; vis[child] = 1; int maxx = 0; node *p = head[father]; while(p != NULL)//找到父节点除child外其他分支的最大价值 { if(p->v != child) maxx = max(maxx, p->sum); p = p->next; } p = head[child]; while(p !=NULL)//继续往上更新,才能保证每步都得到最优解 { if(p->v == father) { p->sum = p->len + maxx; break; } p = p->next; } p = head[child]; while(p != NULL)//每次都更新当前节点,并往下递归计算,父节点会因为vis=1而不计算 { dp[child] = max(dp[child], p->sum); dfs2(child, p->v); p = p->next; } } int main() { int a,b; while(scanf("%d",&n)==1) { init(); for(int i=2; i<=n; i++) { scanf("%d%d",&a,&b); add(i, a, b); } dfs1(1); CL(vis, 0); node *p = head[1]; while(p != NULL) { dfs2(1, p->v); p = p->next; } for(int i=1; i<=n; i++) printf("%d\n",dp[i]); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:树形dp
原文地址:http://blog.csdn.net/d_x_d/article/details/49718455