2011-0057
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
= 题目大意 =
有一颗有N个节点的无向树,每个节点有一个价值Vi,表示有Vi价值的宝物在这个节点(只能取一次),同时每条边有一个长度Li,表示走这条边需要Li天。给定某个点X,求在Mi天回到X的前提下能获取的最大宝物价值。
= 解题报告 =
这题是一个简单的树形动态规划,设Dp[i][j]表示在第i个节点并且已经过了j天的最大宝物获得量,那么假设我们现在处理到第i个节点,并且他的子节点全部处理过了,那么就相当于所有子节点有一个价值(Dp[i.son][k]),有一个重量(k),这就是个经典的0/1背包问题,也就是一个经典的树上背包的动态规划,当然似乎转化为左儿子右兄弟也可以做?总而言之就是这样。最后遍历一下所有Dp[X][i]找到最大值即可。
= 题目代码 =
{{{
#include<cstdio>
#include<cstring>
#define MAXN 1005
#define MAXD 2005
struct EdgeType{
int adj,t;
EdgeType *next;
}Edge[MAXN*10],*Gr[MAXN];
int n,m,root,dp[MAXN][MAXD],e,v[MAXN];
//bool mark[MAXN];
int InsertEdge(int x,int y,int z){
Edge[++e].adj=y;
Edge[e].t=z;
Edge[e].next=Gr[x];
Gr[x]=&Edge[e];
return 0;
}
int Dfs(int now,int pre){
int nowt,j,k;
dp[now][0]=v[now];
for(EdgeType *t=Gr[now];t;t=t->next){
if(t->adj!=pre){
Dfs(t->adj,now);
nowt=t->t;
for(k=m;k>=0;k--)
for(j=0;j<=m;j++)
if(k-j-nowt*2>=0)
if(dp[now][k]<dp[t->adj][j]+dp[now][k-j-nowt*2])
dp[now][k]=dp[t->adj][j]+dp[now][k-j-nowt*2];
}
}
return 0;
}
int main(){
int i,j,bestans,x,y,z;
while(scanf("%d",&n)!=EOF){
memset(Edge,0,sizeof(Edge));
memset(Gr,0,sizeof(Gr));
e=0;
for(i=1;i<=n;i++)scanf("%d",&v[i]);
for(i=1;i<=n-1;i++){
scanf("%d%d%d",&x,&y,&z);
InsertEdge(x,y,z);
InsertEdge(y,x,z);
}
scanf("%d%d",&root,&m);
memset(dp,0,sizeof(dp));
//memset(tp,0,sizeof(tp));
//memset(Dis,0,sizeof(Dis));
//memset(mark,0,sizeof(mark));
//GetDis(root,0);
Dfs(root,0);
bestans=0;
for(j=0;j<=m;j++)
if(dp[root][j]>bestans)bestans=dp[root][j];
printf("%d\n",bestans);
}
}
}}}
Finished by Dai@NeverLand
题目大意
有一颗有N个节点的无向树,每个节点有一个价值Vi,表示有Vi价值的宝物在这个节点(只能取一次),同时每条边有一个长度Li,表示走这条边需要Li天。给定某个点X,求在Mi天回到X的前提下能获取的最大宝物价值。
解题报告
这题是一个简单的树形动态规划,设Dp[i][j]表示在第i个节点并且已经过了j天的最大宝物获得量,那么假设我们现在处理到第i个节点,并且他的子节点全部处理过了,那么就相当于所有子节点有一个价值(Dp[i.son][k]),有一个重量(k),这就是个经典的0/1背包问题,也就是一个经典的树上背包的动态规划,当然似乎转化为左儿子右兄弟也可以做?总而言之就是这样。最后遍历一下所有Dp[X][i]找到最大值即可。
题目代码
#include<cstdio>
#include<cstring>
#define MAXN 1005
#define MAXD 2005
struct EdgeType{
int adj,t;
EdgeType *next;
}Edge[MAXN*10],*Gr[MAXN];
int n,m,root,dp[MAXN][MAXD],e,v[MAXN];
//bool mark[MAXN];
int InsertEdge(int x,int y,int z){
Edge[++e].adj=y;
Edge[e].t=z;
Edge[e].next=Gr[x];
Gr[x]=&Edge[e];
return 0;
}
int Dfs(int now,int pre){
int nowt,j,k;
dp[now][0]=v[now];
for(EdgeType *t=Gr[now];t;t=t->next){
if(t->adj!=pre){
Dfs(t->adj,now);
nowt=t->t;
for(k=m;k>=0;k--)
for(j=0;j<=m;j++)
if(k-j-nowt*2>=0)
if(dp[now][k]<dp[t->adj][j]+dp[now][k-j-nowt*2])
dp[now][k]=dp[t->adj][j]+dp[now][k-j-nowt*2];
}
}
return 0;
}
int main(){
int i,j,bestans,x,y,z;
while(scanf("%d",&n)!=EOF){
memset(Edge,0,sizeof(Edge));
memset(Gr,0,sizeof(Gr));
e=0;
for(i=1;i<=n;i++)scanf("%d",&v[i]);
for(i=1;i<=n-1;i++){
scanf("%d%d%d",&x,&y,&z);
InsertEdge(x,y,z);
InsertEdge(y,x,z);
}
scanf("%d%d",&root,&m);
memset(dp,0,sizeof(dp));
//memset(tp,0,sizeof(tp));
//memset(Dis,0,sizeof(Dis));
//memset(mark,0,sizeof(mark));
//GetDis(root,0);
Dfs(root,0);
bestans=0;
for(j=0;j<=m;j++)
if(dp[root][j]>bestans)bestans=dp[root][j];
printf("%d\n",bestans);
}
}
Finished by Dai@NeverLand