题目大意:按照前序给出一棵完全树的前序,每个节点的值,现在要求在这棵树上切最多k刀,使得获得的值最大,但是有一个要求,就是对于每颗子树来说,最多切一刀,并且每个叶子节点都要被切掉才行。
解题思路:dp[i][k]表示i节点为根的子树,切k刀后的最大值。每个节点都有左孩子和右孩子之分,对于一个状态dp[i][k],枚举左孩子的刀数t,dp[i][k] = max(dp[i][k], dp[i*2+1][t] + dp[i*2+2][k-t]).并且注意dp[i][k]还可以由dp[i][k-1]得到,因为可以切小于k刀。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = (1<<20)+5;
const int K = 25;
const int INF = 0x3f3f3f3f;
int n, k, dp[N][K];
void buildTree(int u, int d) {
if (d > n)
return;
scanf("%d", &dp[u][1]);
buildTree(u*2+1, d+1);
buildTree(u*2+2, d+1);
}
int solve () {
int t = (1<<(n+1))-2;
for (int i = 2; i <= k; i++) {
for (int j = t; j >= 0; j--) {
int p = j*2+1;
int q = j*2+2;
dp[j][i] = dp[j][i-1];
if (p > t || q > t)
continue;
for (int x = 1; x < i; x++)
dp[j][i] = max(dp[j][i], dp[p][x] + dp[q][i-x]);
}
}
return dp[0][k];
}
int main () {
while (scanf("%d", &n) == 1 && n != -1) {
scanf("%d", &k);
buildTree(0, 0);
printf("%d\n", solve());
}
return 0;
}