(树上dp)luogu4438道路

这是一道树上的dp问题,题意是给你一棵满的二叉树(父亲表示法),然后左叉为公路,右叉为铁路,每个非叶子节点都是一个城市,每个叶子节点都是一个乡村,让你翻修n-1条路,每个乡村有一个不便利值,这个值和这个乡村上面没翻修的公路数和铁路数有关,让你求最小不便利值的和。

 

因为树本身的父亲和儿子就有一种关系,所以常用这种关系从父亲递推到儿子。

考虑dp先考虑让做什么事:就是选择一些边使最后权值和最小。

然后考虑状态,一般树上dp都有一维为当前节点i,然后考虑因为我最后到叶子节点时我需要用未翻修的路的数目来求值,所以应该还有两个状态为这条路上翻修了多少条公路多少条铁路,所以状态确定为  f [ i ][ x ][ y ] 表示当前节点i上面未修x条公路,y条铁路。

为何判断出为i上面的呢?因为如果设为i下面的,我在走到i的时候下面修了多少条路我不知道,而且这也不利于到叶子节点时计算值。

 

最后就是转移,f [ i ][ x ][ y ] = min{f [ l [ i ] ][ x+1 ][ y ] + f [ r[ i ] ][ x ][ y ] , f [ l[ i ] ][ x ][ y ] + f[ r[ i ] ][ x ][ y+1 ] }  

第一个决策是选择修铁路,那么左儿子会因此多了一条没翻修的公路,第二个决策是选择修公路,那么右儿子会因此多了一条没翻修的铁路。由于为树形结构,可以写一个记忆化,会好受一点。

#include<iostream>
#include<cstdio>
using namespace std;
int n;
int l[20005],r[20005];
long long a[40010],b[40010],c[40010];
long long f[20005][45][45];
long long dfs(int i,int x,int y)
{
    if(i>=n) return c[i]*(a[i]+x)*(b[i]+y);
    if(f[i][x][y]) return f[i][x][y];
    f[i][x][y]=min(dfs(l[i],x+1,y)+dfs(r[i],x,y),dfs(l[i],x,y)+dfs(r[i],x,y+1));
    return f[i][x][y];
}
void getdata()
{
    scanf("%d",&n);
    int s,t;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d",&s,&t);
        l[i]=s>0?s:n-1-s;
        r[i]=t>0?t:n-1-t;
    }
    for(int i=n;i<n*2;i++)
    {
        scanf("%d%d%d",&a[i],&b[i],&c[i]);
    }
    printf("%lld",dfs(1,0,0));
}
int main()
{
    getdata();
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值