[HNOI/AHOI2018] 道路
题目链接:https://loj.ac/problem/2510
题目很长,但是事实上就是有2n-1个点,然后除了叶子节点,每个节点都有左右两条边(需要注意的是这两条边需要区分)。然后给这些边打标记,最后算叶子节点到根节点的没有打标记的左右两种边分别乘上花费的最小值。。。。(呃,我的解释是不是不太清楚。。qwq)
没有看懂我的解释的还是回去好好看看原题吧qwq看懂题之后我们就可以愉快的做题了。。。
事实上我被卡空间了。。。。卡在514M也很难过啊qwq。。。
但是我太蒻了啊。。不会正解啊qwq
所以我只能放上我的辣鸡代码+思路了。。。
\(f[i][j][k]\)表示从根节点到节点i有j条公路,k条铁路。
\[f[i][j][k]=min(f[lson(i)][j+1][k]+f[rson(i)][j][k],f[lson(i)][j][k]+f[rson(i)][j][k+1])
\]
也就是树形DP嘛。。。。上面的转移方程的意思是选取父节点的哪一条边。。。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#define MAXN 20000
using namespace std;
int n;
int l[MAXN<<1],r[MAXN<<1],a[MAXN<<1],b[MAXN<<1],c[MAXN<<1],len[MAXN<<1];
long long dp[MAXN<<1][41][41];
inline void search(int now)
{
if(now>=n)
{
for(int i=0;i<=40;i++)
for(int j=0;j<=40;j++)
dp[now][i][j]=(long long)c[now]*(a[now]+i)*(b[now]+j);
return;
}
search(l[now]);
search(r[now]);
for(int j=0;j<=40;j++)
for(int k=0;k<=40;k++)
dp[now][j][k]=min(dp[l[now]][j+1][k]+dp[r[now]][j][k],dp[l[now]][j][k]+dp[r[now]][j][k+1]);
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
scanf("%d%d",&l[i],&r[i]);
if(l[i]<0) l[i]=abs(l[i])+n-1;
if(r[i]<0) r[i]=abs(r[i])+n-1;
// printf("l=%d r=%d\n",l[i],r[i]);
}
for(int i=0;i<n;i++)
scanf("%d%d%d",&a[i+n],&b[i+n],&c[i+n]);
search(1);
printf("%lld\n",dp[1][0][0]);
return 0;
}