Description
农夫有n块农田,农田里种满了稻子。秋天到了,稻子熟了,每块农田都有一定数量的稻子。我们可以把农田看成n个点,编号是1到n。农夫起点编号是1。恰好有n-1条道路连接这些点,每条道路长度都为1,并且任意2点都是可达的。每条道路都有一定的长度。现在农夫从起点出发,到农田收割稻子。农夫每经过一块农田就能收割该农田里的稻子。但是农夫是如此的懒惰,他可不想走过的总路程超过m。农夫应该如何选择一种收割方案使得到的稻子最多。农夫最后可以停在任意点!
Input
第一行一个正整数n(1<=n<=100)表示农田数;
第二行n个整数(不大于1000)表示每块农田的稻子数。
接着n-1行每行两个整数a,b,表示a和b之间有一条长度为1的道路,道路是双向的。
最后一行一个整数m(0<=m<=200)表示农夫最多走m的路程。
Output
输出一个整数,表示农夫能得到最多的稻子。
Sample Input
2
1 1
1 2
1
Sample Output
2
md考试的时候脑子一抽数组开小了。。。
这是一道树上背包的一类模板题。写的时候注意几个细节:
1、更新的时候从大到小(嗯,背包的做法)
2、注意处理的顺序,保证用第i棵子树时,前i-1的答案不会被重复优化
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
struct Edge{
int cnt,h[N],to[N<<1],next[N<<1];
inline void add(int x,int y){
next[++cnt]=h[x];
to[cnt]=y;
h[x]=cnt;
}
}e;
int n,m,a[N];
inline void init(){
scanf("%d",&n);
for(register int i=1;i<=n;++i)scanf("%d",&a[i]);
for(int i=1;i<n;++i){
int x,y;scanf("%d%d",&x,&y);
e.add(x,y),e.add(y,x);
}
scanf("%d",&m);
}
int f[110][210];//以i为根,
int g[110][210];//不回到根
#define to e.to[p]
void dp(int x,int fa){
f[x][0]=g[x][0]=a[x];
for(int p=e.h[x];p;p=e.next[p])if(to^fa){
dp(to,x);
for(int i=m;i>0;--i)
for(int j=0;i-j-2>=0;++j)
f[x][i]=max(f[x][i],g[to][j]+f[x][i-j-2]);
for(int i=m;i>0;--i)
for(int j=0;i-j-1>=0;++j)
f[x][i]=max(f[x][i],g[x][j]+f[to][i-j-1]);
for(int i=m;i>0;--i)
for(int j=0;i-j-2>=0;++j)
g[x][i]=max(g[x][i],g[x][j]+g[to][i-j-2]);
}
for(int i=1;i<=m;++i)
f[x][i]=max(f[x][i],f[x][i-1]),g[x][i]=max(g[x][i],g[x][i-1]);
}
int main(){
init();
dp(1,0);
cout<<f[1][m]<<"\n";
return 0;
}
//5
//10 11 32 41 35
//1 2
//1 3
//2 5
//2 4
//10