A组
T1.dostavljac 餐馆
树形DP,怎么处理走回来呢?考场想了f[i][j][0/1]表示以i为根子树,用了j秒,并且选/不选当前点,不能转移,为什么呢?因为这个第三维完全没用,可以在一开始就考虑。
正解f[i][j][0/1]表示以i为根的子树,用了j秒,并且回到/不回到当前点,这样就可以分类转移了。
转移时考虑做到子树v,分三类讨论。
注意一个点只能选一次,倒序循环。
#include<iostream> #include<cstdio> using namespace std; inline int rd(){ int ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } const int MAXN=1005; struct Edge{ int next,to; }e[MAXN]; int ecnt,head[MAXN],ind[MAXN]; inline void add(int x,int y){ e[++ecnt].next = head[x]; e[ecnt].to = y; head[x] = ecnt; } int n,m; int f[MAXN][MAXN*2][2]; int a[MAXN]; int ans=0; void dfs(int x,int pre){ f[x][1][0]=f[x][1][1]=a[x]; int tmp=0,mx=0; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(v==pre) continue; dfs(v,x); for(int j=m;j>=0;j--){ for(int k=m-j-1;k>=0;k--){ f[x][j+k+2][0]=max(f[x][j+k+2][0],f[x][j][0]+f[v][k][0]); f[x][j+k+2][1]=max(f[x][j+k+2][1],f[x][j][1]+f[v][k][0]); f[x][j+k+1][1]=max(f[x][j+k+1][1],f[x][j][0]+f[v][k][1]); } } } } void solve(){ dfs(1,0); cout<<max(f[1][m][1],f[1][m][0]); } int main(){ freopen("dostavljac.in","r",stdin); freopen("dostavljac.out","w",stdout); n=rd();m=rd(); int x,y; for(int i=1;i<=n;i++) a[i]=rd(); for(int i=1;i<=n-1;i++){ x=rd();y=rd(); add(x,y);add(y,x); } solve(); return 0; }