【2010福建】收稻子
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
思路
- f[i][j]表示以i为根的子树,以i为起点,最多走j的路程,又回到了i,得到的最多麦子数
- g[i][j]表示以i为根的子树,以i为起点,最多走j的路程,不回i,得到的最多麦子数
- 题目
农夫最后可以停在任意点
,不回i出发不回到i的边应该只有一条 - u为v的父节点,有方程:
g[u][i]=max(g[u][i],g[u][i-j-2]+f[v][j]);//有边不回到u
g[u][i]=max(g[u][i],f[u][i-j-1]+g[v][j]);//走u后不回来
f[u][i]=max(f[u][i],f[u][i-j-2]+f[v][j]);//所有都回来
//-2,-1解释:-2,从u到v再回来耗费路程2,不会来耗费路程1
代码
#include <iostream>
#include <cstdio>
using namespace std;
int n,cnt,head[105],m,f[105][205],g[105][205],val[105];
struct fdfdfd{int to,next;}e[205];
void addedge(int x,int y){e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt;}
void dfs(int u,int fa)
{
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa) continue;
dfs(v,u);
for(int i=m;i>=0;--i)
for(int j=0;j<=i-2;++j) g[u][i]=max(g[u][i],g[u][i-j-2]+f[v][j]);
for(int i=m;i>=0;--i)
for(int j=0;j<=i-1;++j) g[u][i]=max(g[u][i],f[u][i-j-1]+g[v][j]);
for(int i=m;i>=0;--i)
for(int j=0;j<=i-2;++j) f[u][i]=max(f[u][i],f[u][i-j-2]+f[v][j]);
}
for(int i=0;i<=m;++i) g[u][i]+=val[u],f[u][i]+=val[u];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&val[i]);
for(int i=1,u,v;i<n;++i) scanf("%d%d",&u,&v),addedge(u,v),addedge(v,u);
scanf("%d",&m);
dfs(1,0);
int ans=0;
for(int i=1;i<=m;++i) ans=max(ans,g[1][i]);
printf("%d\n",ans);
return 0;
}