bzoj5290 [Hnoi2018]道路(树形dp)

妈妈终于有我会做的题了x
f[x][i][j]表示x节点上面有i条公路未修,j条铁路未修的最小花费。
叶子节点直接算贡献,其他节点无非两种决策,修公路/铁路,相应的儿子状态的和取最小即可。
i+j<=40.
直接开空间开不下可以压一下。
复杂度 O(n202) O ( n 20 2 )

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 20010
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,ya[N],yb[N],a[N],b[N],c[N];
ll f[N<<1][450];
void dfs(int x,int na,int nb){
    if(x>n){
        for(int i=0;i<=na;++i)
            for(int j=0;j<=nb;++j)
                f[x][i*(nb+1)+j]=(ll)(a[x-n]+i)*(b[x-n]+j)*c[x-n];return;
    }dfs(ya[x],na+1,nb);dfs(yb[x],na,nb+1);
    for(int i=0;i<=na;++i)
        for(int j=0;j<=nb;++j)
            f[x][i*(nb+1)+j]=min(f[ya[x]][(i+1)*(nb+1)+j]+f[yb[x]][i*(nb+2)+j],f[ya[x]][i*(nb+1)+j]+f[yb[x]][i*(nb+2)+j+1]);
}
int main(){
//  freopen("a.in","r",stdin);
    n=read();memset(f,inf,sizeof(f));
    for(int i=1;i<=n-1;++i){
        ya[i]=read(),yb[i]=read();
        if(ya[i]<0) ya[i]=-ya[i]+n;if(yb[i]<0) yb[i]=-yb[i]+n;
    }for(int i=1;i<=n;++i) a[i]=read(),b[i]=read(),c[i]=read();
    dfs(1,0,0);
    printf("%lld\n",f[1][0]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值