Each test case contains three parts.
The first part is two numbers N K, whose meanings we have talked about just now. We denote the nodes by 1 2 ... N. Since it is a tree, each node can reach any other in only one route. (1<=N<=100, 0<=K<=200)
The second part contains N integers (All integers are nonnegative and not bigger than 1000). The ith number is the amount of apples in Node i.
The third part contains N-1 line. There are two numbers A,B in each line, meaning that Node A and Node B are adjacent.
Input will be ended by the end of file.
Note: Wshxzt starts at Node 1.
2 1 0 11 1 2 3 2 0 1 2 1 2 1 3
11 2这个题我还不是很理解,大概知道思路,给出大神的讲解
题意:一颗树,n个点(1-n),n-1条边,每个点上有一个权值,求从1出发,走V步,最多能遍历到的权值
我们把背包的思想用到这里来,做的步数相当于背包的容量,点上的权值相当于价值,给定一定的背包容量,求最多能装进背包的价值
设dp[0][s][j]表示从s(当前根节点)出发,走 j 步,回到s所能获得的最大权值
dp[1][s][j]表示从s(当前根节点)出发,走j步,不回到s所能获得的最大权值
现在我们就可以分配背包容量了:父节点与子节点分配背包容量,从而设计出状态转移方程
主要思想:
s返回,t返回
s不返回,t返回(走向t子树,t子树返回之后走向s的其他子树,然后不回到s)
s返回,t不返回(遍历s的其他子树后返回s,返回之后走向t子树,然后不回到t)
没有都不返回,肯定有一方有一个返回的过程,再去另一边的子树的
总结起来一句话,要么去s的其他子树呆着,要么去t子树呆着,要么回到s点
1、在t子树返回,其他子树也返回,即回到当前根节点s
2,、不返回根节点,但在t子树返回,即相当于从t出发走k步返回t的最优值 加上 从s出发走j-k步到其他子树不返回的最优值,中间有s与t连接起来,其实就等于从s出发遍历t子树后(dp[0][t][k])又回到s(这一步多了中间的来回两步),再走出去(其他子树)【dp[1][s][j-k]】,不回来
3、不返回根节点,在t子树也不返回,等价于从s出发遍历其他子树,回到s(dp[0][s][j-k]),再走向t子树,不回到t(dp[1][t][k]),这个过程s-t只走了一步
dp[0][s][j+2]=Max(dp[0][s][j+2],dp[0][t][k]+dp[0][s][j-k]);//从s出发,要回到s,需要多走两步s-t,t-s,分配给t子树k步,其他子树j-k步,都返回
dp[1][s][j+2]=Max(dp[1][s][j+2],dp[0][t][k]+dp[1][s][j-k]);//不回到s(去s的其他子树),在t子树返回,同样有多出两步
dp[1][s][j+1]=Max(dp[1][s][j+1],dp[1][t][k]+dp[0][s][j-k]);//先遍历s的其他子树,回到s,遍历t子树,在当前子树t不返回,多走一步
#include<stdio.h>
int vist[105],node[105][105],len[105],val[105],step;
int dp[2][105][205];//dp[1][p][k]表示用k步(k仅仅只用于以节点p为根的子树,不包含从p的父节点走到p的步数)(最终)人还在节点p(根节点是相对于子节点而言)
int max(int a,int b)
{
return a>b?a:b;
}
void dfs(int p)
{
for(int i=0;i<=step;i++)//注意从0开始
dp[0][p][i]=dp[1][p][i]=val[p];
vist[p]=1;
for(int i=1;i<=len[p];i++)
{
int son=node[p][i];
if(vist[son])continue;
dfs(son);
for(int s=step;s>=1;s--)//以p为根的子树固定步数s
for(int st=0;st<=s-1;st++)//子节点(树)的步数st
{
if(s-st-2>=0)
{
dp[1][p][s]=max(dp[1][p][s],dp[1][p][s-st-2]+dp[1][son][st]);
dp[0][p][s]=max(dp[0][p][s],dp[0][p][s-(st+2)]+dp[1][son][st]);//(st+2)表示的是能从p到son,并从son到p
//(这里面减2是为了保证连续性,)遍历了son以前的子节点中其中一个没有反回根节点,但必须保证能从son节点反回根节点p,所以最终没回到p
}
dp[0][p][s]=max(dp[0][p][s],dp[1][p][s-st-1]+dp[0][son][st]);//同样要保证连续性,跟上述同理
}
}
}
int main()
{
int n,a,b,max;
while(scanf("%d%d",&n,&step)>0)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&val[i]);
len[i]=0,vist[i]=0;
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&a,&b);
len[a]++; node[a][len[a]]=b;
len[b]++; node[b][len[b]]=a;
}
dfs(1);
max=dp[0][1][step];
if(max<dp[1][1][step])
max=dp[1][1][step];
printf("%d\n",max);
}
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
vector<int>g[1010];
int dp[2][1010][210];
int n,V,val[1010];
bool used[1010];
void Max(int &a,int b){
if(a<b)
a=b;
}
void dfs(int s){
int i;
used[s]=true;
for(i=0;i<=V;i++){
dp[0][s][i]=dp[1][s][i]=val[s];
}
for(i=0;i<g[s].size();i++){
int t=g[s][i];
if(used[t])continue;
dfs(t);
for(int j=V;j>=0;j--){
for(int k=0;k<=j;k++){
Max(dp[0][s][j+2],dp[0][t][k]+dp[0][s][j-k]);
Max(dp[1][s][j+2],dp[0][t][k]+dp[1][s][j-k]);
Max(dp[1][s][j+1],dp[1][t][k]+dp[0][s][j-k]);
}
}
}
}
int main(){
int i,a,b;
while(~scanf("%d %d",&n,&V)){
for(i=0;i<=1000;i++)
g[i].clear();
for(i=1;i<=n;i++)
scanf("%d",&val[i]);
for(i=0;i<n-1;i++){
scanf("%d%d",&a,&b);
g[a].push_back(b);
g[b].push_back(a);
}
memset(dp,0,sizeof(dp));
memset(used,false,sizeof(used));
dfs(1);
printf("%d\n",dp[1][1][V]);
}
return 0;
}
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
struct node{
int u,v,val,next;
}tree[505];
int dp[205][405][2],head[205],val[205];
int len,n,k;
void add(int u,int v){
tree[len].u=u;
tree[len].v=v;
tree[len].next=head[u];
head[u]=len++;
}
void dfs(int root,int mark){
int i,j,t,son;
for(i=head[root];i!=-1;i=tree[i].next){
son=tree[i].v;
if(son==mark)
continue;
dfs(son,root);
for(j=k;j>=1;j--){
for(t=1;t<=j;t++){
dp[root][j][0]=max(dp[root][j][0],dp[root][j-t][1]+dp[son][t-1][0]);
dp[root][j][0]=max(dp[root][j][0],dp[root][j-t][0]+dp[son][t-2][1]);
dp[root][j][1]=max(dp[root][j][1],dp[root][j-t][1]+dp[son][t-2][1]);
}
}
}
}
int main(){
int i,j,a,b;
while(~scanf("%d %d",&n,&k)){
memset(dp,0,sizeof(dp));
memset(head,-1,sizeof(head));
for(i=1;i<=n;i++){
scanf("%d",&val[i]);
for(j=0;j<=k;j++){
dp[i][j][0]=dp[i][j][1]=val[i];
}
}
len=0;
for(i=1;i<n;i++){
scanf("%d %d",&a,&b);
add(a,b);
add(b,a);
}
dfs(1,0);
printf("%d\n",max(dp[1][k][0],dp[1][k][1]));
}
return 0;
}