1. 程式人生 > >[HNOI 2018]道路

[HNOI 2018]道路

else long long fine com display scrip inline set names

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\)

,二叉樹深度不超過 \(40\)

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]道路