Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 6148 | Accepted: 1986 |
Description
Input
Output
Sample Input
2 1 0 11 1 2 3 2 0 1 2 1 2 1 3
Sample Output
11 2
题意:有一颗苹果树,每个节点上面有很多苹果,从一个节点到另外一个可以到达的节点花费1步,求k步最多能吃到多少苹果。
这是典型的回溯型树状dp。dp[0][i][j]代表以i为根节点的子树最多j步后回到i能吃到的最多的苹果,dp[1][i][j]代表以i为根节点的子树最多j步后不回到i节点最多能吃到的子树。那么状态转移就分三步了。
(1)dp[0][i][j] = max(dp[0][i][j], dp[0][i][j-k]+dp[0][son-2][k]);
(2)dp[1][i][j]] = max(dp[1][i][j], dp[0][i][j-k]+dp[1][son-1][k]); 人留在i的子节点son的子树中
(3)dp[1][i][j] = max(dp[1][i][j], dp[1][i][j-k]+dp[0][son-2][k]); 人留在不是son的i的子节点的子树中
#include<cstdio> #include<cstring> #include<vector> using namespace std; #define Max_(a,b) (a>b?a:b) int N,K; int Val[200],S[200]; bool vis[200]; int d[2][200][300]; vector<int> Son[200]; void DFS(int x) { int i,j,u,m; d[0][x][0]=Val[x]; d[1][x][0]=Val[x]; for(i=0;i<Son[x].size();i++) { if(vis[Son[x][i]]) continue; u=Son[x][i]; vis[u]=1; DFS(u); for(j=K;j>=0;j--) { for(m=1;m<=j;m++) { if(m>=2) { d[0][x][j]=Max_(d[0][x][j],d[0][x][j-m]+d[0][u][m-2]); d[1][x][j]=Max_(d[1][x][j],d[1][x][j-m]+d[0][u][m-2]); } d[1][x][j]=Max_(d[1][x][j],d[0][x][j-m]+d[1][u][m-1]); } } } } int main() { int a,b; int i; while(scanf("%d%d",&N,&K)==2) { for(i=1;i<=N;i++) { scanf("%d",&Val[i]); Son[i].clear(); } for(i=1;i<N;i++) { scanf("%d%d",&a,&b); Son[a].push_back(b); Son[b].push_back(a); } memset(vis,0,sizeof(vis)); memset(d,0,sizeof(d)); vis[1]=1; DFS(1); int max=0; for(i=0;i<=K;i++) { max=Max_(max,d[0][1][i]); max=Max_(max,d[1][1][i]); } printf("%d\n",max); } return 0; }