【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;
}
posted @ 2020-09-09 17:13  wuwendongxi  阅读(120)  评论(0编辑  收藏  举报