您的位置:首页 > 其它

【动态规划】[NOIP2003]加分二叉树

2017-10-29 19:58 363 查看
题目

感觉这个题挺难的啊 毕竟dp很弱

一个比较经典的树形dp

我们用f[i][j]表示区间i~j的最大加分 dp[i][j]表示区间i~j的最大加分时的根节点是什么 所以初始化f[i][i] = a[i] dp[i][i] = i

然后就是循环枚举区间 然后在每个区间中在枚举根节点 如果发现当前区间的左子树的加分×右子树的加分 + 根的分数大于当前的f[i][j]就更新

最后还要输出一个前序遍历 也就是头左右 深搜一下即可

代码如下

#include<iostream>
#include<cstdio>
#include<cctype>

using namespace std;
#define in = read()
typedef long long ll;
typedef unsigned int ui;
const ll size = 100 + 1;

int n , l , r;
int a[size] , f[size][size] , dp[size][size];

inline ll read(){
ll num = 0 , f = 1;     char ch = getchar();

while(!isdigit(ch)){
if(ch == '-')   f = -1;
ch = getchar();
}
while(isdigit(ch)){
num = num*10 + ch - '0';
ch = getchar();
}

return num*f;
}

void dfs(int x , int y){
printf("%d " , dp[x][y]);
if(dp[x][y] > x)    dfs(x , dp[x][y] - 1);
if(dp[x][y] < y)    dfs(dp[x][y] + 1 , y);
}

int main(){
n in;
for(register int i=1;i<=n;i++){
a[i] in;
f[i][i] = a[i];
dp[i][i] = i;
}

int j;
for(register int u=2;u<=n;u++)
for(register int i=1;i+u-1<=n;i++){
j = i + u - 1;
for(register int k=i;k<=j;k++){
l = f[i][k - 1];    r = f[k + 1][j];
if(k == i && k != j)    l = 1;
if(k == j && k != i)    r = 1;
if(f[i][j] < l*r + f[k][k]){
dp[i][j] = k;
f[i][j] = l*r + f[k][k];
}
}
}
printf("%d\n" , f[1]
);
dfs(1 , n);

return 0;
}

//COYG
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: