[bzoj5290][Hnoi2018]道路【树形dp】
【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=5290
https://www.luogu.org/problemnew/show/P4438
【题解】
记表示现在在号点从根节点到这个点经过了条未被修缮的公路和条未被修缮的铁路的答案。
于是有:
为公路连接的儿子,为铁路连接的儿子。
叶子节点的答案直接计算即可,注意在用到的时候再算,否则可能会爆空间。
最后的答案为
时间复杂度: D为深度。
# include <bits/stdc++.h>
# define N 20010
# define T 41
# define ll long long
# define inf 0x3f3f3f3f
using namespace std;
int read(){
int tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
int son[N][2],n;
ll f[N][T][T],v[N][3];
ll calc(int x, int i, int j){
return v[x-n+1][2]*(v[x-n+1][0]+i)*(v[x-n+1][1]+j);
}
void dfs(int x, int num0, int num1){
if (x>=n) return;
else {
dfs(son[x][0],num0+1,num1);
dfs(son[x][1],num0,num1+1);
for (int i=0; i<=num0; i++)
for (int j=0; j<=num1; j++){
ll tmp00, tmp01, tmp10, tmp11;
if (son[x][0]>=n)
tmp00=calc(son[x][0],i,j),tmp01=calc(son[x][0],i+1,j);
else tmp00=f[son[x][0]][i][j],tmp01=f[son[x][0]][i+1][j];
if (son[x][1]>=n)
tmp10=calc(son[x][1],i,j),tmp11=calc(son[x][1],i,j+1);
else tmp10=f[son[x][1]][i][j],tmp11=f[son[x][1]][i][j+1];
f[x][i][j]=min(tmp00+tmp11,tmp01+tmp10);
}
}
}
int main(){
n=read();
for (int i=1; i<n; i++){
int u=read(), v=read();
if (u<0) u=-u+(n-1);
if (v<0) v=-v+(n-1);
son[i][0]=u;
son[i][1]=v;
}
for (int i=1; i<=n; i++){
v[i][0]=read();
v[i][1]=read();
v[i][2]=read();
}
memset(f,inf,sizeof(f));
dfs(1,0,0);
printf("%lld\n",f[1][0][0]);
return 0;
}