POJ 2486 Apple Tree

来源:互联网 发布:网络维护公司简介 编辑:程序博客网 时间:2024/05/17 13:08

树形DP+背包

题意:给一棵树,每个点有相应的价值,要求从节点1开始走最多k步,问能取得的最大价值。重复经过的点不算。

分析:这题的特点是走到叶子节点后回返也需要消耗步数。

思路:设状态g[i][j]表示以i为根的子树走j步不回到根的最大价值,状态b[i][j]表示以i为根的子树走j步最后回到根的最大价值

所以 b[u][i+j+2] = max(b[u][i+j+2], b[u][i]+b[v][j]);

然后g的求法是,因为对一个根来说,他的不返回的子树最多只有一个,所以枚举他的不返回子树,其他子树记返回即可。

略牛逼的状态啊,果断是看别人才懂的。。

#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;int max(int a, int b) { return a>b?a:b; }int min(int a, int b) { return a<b?a:b; }const int MAXN = 210;int g[MAXN][MAXN],b[MAXN][MAXN];int tt[MAXN];int n,k;struct E{int v,next;}edge[MAXN<<1];int head[MAXN],tot;void add_edge(int a, int b){edge[tot].next = head[a];edge[tot].v = b;head[a] = tot ++;}void dfs(int u, int fa){int p,i,j;int maxt;for(p=head[u]; p!=-1; p=edge[p].next){int v = edge[p].v;if(v == fa) continue;dfs(v,u);for(i=k; i>=0; i--){if(b[u][i] < 0) continue;for(j=0; j+i+2<=k; j++){if(b[v][j] < 0) continue;b[u][i+j+2] = max(b[u][i+j+2], b[u][i]+b[v][j]);}}}for(p=head[u]; p!=-1; p=edge[p].next){int v = edge[p].v;if(v == fa) continue;for(i=1; i<=k; i++) tt[i] = -1;tt[0] = b[u][0];for(int p1 = head[u]; p1!=-1; p1=edge[p1].next){int v1 = edge[p1].v;if(v1 == fa) continue;if(v1 == v){for(i=k; i>=0; i--){if(tt[i] < 0) continue;for(j=0; j+i+1<=k; j++){maxt = max(g[v1][j], b[v1][j]);if(maxt < 0) continue;tt[i+j+1] = max(tt[i+j+1], tt[i]+maxt);}}}else{for(i=k; i>=0; i--){if(tt[i] < 0) continue;for(j=0; j+i+2<=k; j++){if(b[v1][j] < 0) continue;tt[i+j+2] = max(tt[i+j+2], tt[i]+b[v1][j]);}}}}for(i=0; i<=k; i++){if(tt[i] > g[u][i]) g[u][i] = tt[i];}}}int main(){int i;int a,c;while(~scanf("%d%d", &n, &k)){memset(g, -1, sizeof(g));memset(b, -1, sizeof(b));memset(head, -1, sizeof(head));tot = 0;for(i=1; i<=n; i++){scanf("%d", &g[i][0]);b[i][0] = g[i][0];}for(i=1; i<=n-1; i++){scanf("%d%d", &a, &c);add_edge(a,c);add_edge(c,a);}dfs(1,-1);int maxn = 0;for(i=0; i<=k; i++){maxn = max(maxn, max(g[1][i], b[1][i]));}printf("%d\n", maxn);}return 0;}


原创粉丝点击