POJ 2486 Apple Tree(树形DP+分组背包)
http://poj.org/problem?id=2486
应该是做的第二道树形DP+背包问题
题意:有颗苹果树n个节点,n-1条边,每个节点上有一定数量的苹果,每经过一条边花费一个单位时间,一共给了T个单位时间
一棵树,从一个节点到另一个节点,如果不是父子关系的话,就要先返回父节点,再到另一个节点;总共给了T个单位时间,最后
不一定再哪个节点,所以还有访问完子节点是否返回根节点的问题,为了表示是否返回,定义状态dp[i][j][0]表示不返回,
dp[i][j][1]表示返回。这题就应该是这两点不好想吧。考虑好这两点,其它的就是考虑好转移过程了,理解好背包问题,不算难。
代码:
//注意的是加边的时候,没说谁是根
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define nMAX 120
using namespace std;
int num[nMAX],val[nMAX],head[nMAX],s_edge;
int dp[nMAX][nMAX*2][2];
int n,T;
int max(int a,int b)
{
return a>b?a:b;
}
int min(int a,int b)
{
return a<b?a:b;
}
struct Edge
{
int v,nxt;
}edge[nMAX*2];
void addedge(int u,int v)
{
s_edge++;
edge[s_edge].v=v;
edge[s_edge].nxt=head[u];
head[u]=s_edge;
}
void dfs1(int u,int fa)
{
num[u]=0;
for(int e=head[u];e;e=edge[e].nxt)
{
int v=edge[e].v;
if(v==fa) continue;
dfs1(v,u);
num[u]+=(num[v]+2);
}
num[u]=min(num[u],T);
}
void dfs2(int u,int fa)
{
int i,j;
for(int e=head[u];e;e=edge[e].nxt)
{
int v=edge[e].v;
if(v==fa) continue;
dfs2(v,u);
for(i=num[u];i>=0;i--)
for(j=0;j<=num[v];j++)
{
//不能返回的
if(i-j-1>=0)
{
dp[u][i][0]=max(dp[u][i][0],dp[u][i-j-1][1]+dp[v][j][0]);
dp[u][i][0]=max(dp[u][i][0],dp[u][i-j-1][1]+dp[v][j][1]);
}
if(i-j-2>=0) dp[u][i][0]=max(dp[u][i][0],dp[u][i-j-2][0]+dp[v][j][1]);
//能返回的
if(i-j-2>=0)
dp[u][i][1]=max(dp[u][i][1],dp[u][i-j-2][1]+dp[v][j][1]);
}
}
}
int main()
{
int i,j,k;
while(~scanf("%d%d",&n,&T))
{
for(i=1;i<=n;i++) scanf("%d",&val[i]);
memset(head,0,sizeof(head));
s_edge=0;//开始这里怎么就写成edge++了呢??RE了好几次。。。
for(i=1;i<n;i++)
{
scanf("%d%d",&j,&k);
addedge(j,k);
addedge(k,j);
}
dfs1(1,-1);//预处理,计算每个点最多花费的时间
//memset(dp,0,sizeof(dp));
for(i=1;i<=n;i++)
for(j=0;j<=T;j++)
{
dp[i][j][0]=dp[i][j][1]=0;
}
for(i=1;i<=n;i++) dp[i][0][1]=val[i];
dfs2(1,-1);
int ans=0;
for(i=0;i<=num[1];i++)
{
ans=max(ans,dp[1][i][0]);
ans=max(ans,dp[1][i][1]);
}
printf("%d\n",ans);
}
return 0;
}

浙公网安备 33010602011771号