【POJ 2486】 Apple Tree(树型dp)
Time Limit: 1000MS | Memory Limit: 65536K | |
Total Submissions: 8981 | Accepted: 2990 |
Description
Input
Output
Sample Input
2 1 0 11 1 2 3 2 0 1 2 1 2 1 3
Sample Output
11 2
Source
难得1A 不枉这两天跟树dp天天见。。。
题目大意:一棵树。。。还是一棵树……每个节点有一个点权,从树根出发,最远走k步,每走到一个新点,可以把该点的权值累加进去,问最多可以走出多大的权值和。
比较裸的树dp了。dp[i][j][0/1]表示根节点i开始走j步可以走出的最大权值和。最近做树型dp蛮多,发现大多都是这样,要开两个三维空间,一个表示答案,一个是用来辅助求解的。
此题同样,0表示走j步不回到根,1表示最终回到根。
这样发现每个u来说,新遍历到一个孩子v,
dp[u][i][1]的更新为dp[u][i-j-2][1]+dp[v][j][1] 也就是说加上u到v这一步和从v遍历完返回u的v到u这步还有从v出发j步回到v 组成i
dp[u][i][0]的更新有两种,一种是到v后往后走完不回根 dp[u][i][0] = dp[u][i-j-1][1]+dp[v][j][0]
一种是v往后走完回根,然后从之前某个节点走完不回根 dp[u][i][0] = dp[u][i-j-2][0]+dp[v][j][1]
当然 上面这些都要取最大
代码如下:
#include <iostream> #include <cmath> #include <vector> #include <cstdlib> #include <cstdio> #include <cstring> #include <queue> #include <stack> #include <list> #include <algorithm> #include <map> #include <set> #define LL long long #define Pr pair<int,int> #define fread() freopen("in.in","r",stdin) #define fwrite() freopen("out.out","w",stdout) using namespace std; const int INF = 0x3f3f3f3f; const int msz = 10000; const int mod = 1e9+7; const double eps = 1e-8; bool mp[111][111]; //0不回 1回 int dp[111][222][2]; int n,k; int val[111]; void dfs(int u,int pre) { dp[u][0][0] = dp[u][0][1] = val[u]; for(int v = 1; v <= n; ++v) { if(v == pre || !mp[u][v]) continue; dfs(v,u); for(int i = k; i > 0; --i) { for(int j = 0; j < i; ++j) { if(j+2 <= i) { dp[u][i][1] = max(dp[u][i][1],dp[u][i-j-2][1]+dp[v][j][1]); dp[u][i][0] = max(dp[u][i][0],dp[u][i-j-2][0]+dp[v][j][1]); } dp[u][i][0] = max(dp[u][i][0],dp[u][i-j-1][1]+dp[v][j][0]); } } } } int main() { //fread(); //fwrite(); int u,v; while(~scanf("%d%d",&n,&k)) { memset(mp,0,sizeof(mp)); for(int i = 1; i <= n; ++i) scanf("%d",&val[i]); for(int i = 1; i < n; ++i) { scanf("%d%d",&u,&v); mp[u][v] = mp[v][u] = 1; } memset(dp,0,sizeof(dp)); dfs(1,1); int id = k; while(id && !dp[1][id][0]) --id; printf("%d\n",dp[1][id][0]); } return 0; }