[HNOI 2018]道路
阿新 • • 發佈:2018-04-22
else long long fine com display scrip inline set names ,二叉樹深度不超過 \(40\) 。
Description
題庫鏈接
給出一棵含有 \(n\) 個葉子節點的二叉樹,對於每個非葉子節點的節點,其與左兒子相連的邊為公路,其與右兒子相連的邊為鐵路。對於每個節點,選擇一條與其兒子相連的鐵路或公路。對於每個葉子節點 \(u\) ,含有三個參數 \(a,b,c\) ,記 \(u\) 到根節點一共需要經過 \(x\) 條未選擇的公路與 \(y\) 條未選擇的鐵路,其代價為
\[c_u \cdot (a_u + x) \cdot (b_u + y)\]
求最小的總代價和。
\(n \le 20000\) , \(1 \le a_i,b_i \le 60\) , \(1 \le c_i \le 10^9\)
Solution
傳說中的普及 \(dp\) 。
記 \(f_{i,j,k}\) 為 \(i\) 這個節點到根節點路徑上一共需要經過 \(j\) 條未選擇的公路與 \(k\) 條未選擇的鐵路,其子樹中最小的代價和。
答案就是 \(f_{1,0,0}\) 。
轉移就是考慮當前節點選擇鐵路還是選擇公路。
時間復雜度和空間復雜度為 \(O(40^2n)\) 。
Code
#include <bits/stdc++.h>
#define ll long long
#define F(o, i, j) (1ll*c[o]*(i+a[o])*(j+b[o]))
using namespace std;
const int N = 20000+5;
int n, a[N], b[N], c[N], ls[N], rs[N];
ll f[N][41][41];
void dfs(int o, int dep) {
if (o < 0) return;
int l = ls[o], r = rs[o];
dfs(l, dep+1), dfs(r, dep+1);
for (int i = 0; i <= dep; i++)
for (int j = 0; j <= dep; j++) {
if (l < 0 && r < 0) f[o][i][j] = min(F(-l, i+1, j)+F(-r, i, j), F(-l, i, j)+F(-r, i, j+1));
else if (l < 0) f[o][i][j] = min(F(-l, i+1, j)+f[r][i][j], F(-l, i, j)+f[r][i][j+1]);
else if (r < 0) f[o][i][j] = min(f[l][i+1][j]+F(-r, i, j), f[l][i][j]+F(-r, i, j+1));
else f[o][i][j] = min(f[l][i+1][j]+f[r][i][j], f[l][i][j]+f[r][i][j+1]);
}
}
void work() {
scanf("%d", &n);
memset(f, 127/3, sizeof(f));
for (int i = 1; i < n; i++) scanf("%d%d", &ls[i], &rs[i]);
for (int i = 1; i <= n; i++) scanf("%d%d%d", &a[i], &b[i], &c[i]);
dfs(1, 0);
printf("%lld\n", f[1][0][0]);
}
int main() {work(); return 0; }
[HNOI 2018]道路