博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

洛谷 P4438 [HNOI/AHOI2018]道路 解题报告

题面

给你一个二叉树。

每个叶节点的贡献为:ci*(左边标记次数+ai)*(右边标记次数+bi)。

使该贡献最小。


 

考虑树形dp(记搜)。

IDEA:

  1. 搜到叶节点时直接计算值返回。
  2. 搜到已搜过的节点直接返回。
  3. 否则,考虑两种情况:将左边标记/将右边标记。

(题解区大佬的压空间有点看不太懂。于是蒟蒻就选择了这种方法……代码也很短x.)

 

#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline void read(ll &a) {a=0;int c=getchar(),b=1; while(c>'9'||c<'0') {if(c=='-')b=-1;c=getchar();} while(c>='0'&&c<='9') a=(a<<3)+(a<<1)+c-48,c=getchar();a*=b; }
/**/
const int N=20005;
const ll inf=0x3f3f3f3f3f3f3f3fll;
ll n,a[N],b[N],c[N],ls[N],rs[N],f[N][45][45];
/**/
ll dfs(ll u,ll x,ll y)
{
    if(f[u][x][y]!=inf) return f[u][x][y];
    if(u<0) return c[-u]*(a[-u]+x)*(b[-u]+y);
    return f[u][x][y]=min(dfs(ls[u],x,y)+dfs(rs[u],x,y+1),dfs(ls[u],x+1,y)+dfs(rs[u],x,y));
}
int main()
{
    memset(f,0x3f,sizeof(f));
    read(n);
    for(int i=1;i<n;i++) read(ls[i]),read(rs[i]);
    for(int i=1;i<=n;i++) read(a[i]),read(b[i]),read(c[i]);
    cout<<dfs(1,0,0);
}
View Code

 

posted @ 2019-03-18 16:52  楚泫  阅读(97)  评论(0编辑  收藏  举报