5290: [Hnoi2018]道路
分析:
注意题目中说每个城市翻新一条连向它的公路或者铁路,所以两种情况分别转移一下即可。
注意压一下空间,最后的叶子节点不要要访问,空间少了一半。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<iostream> #include<cctype> #include<set> #include<vector> #include<queue> #include<map> #define fi(s) freopen(s,"r",stdin); #define fo(s) freopen(s,"w",stdout); using namespace std; typedef long long LL; inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 40001; int head[N], ls[N], rs[N], a[N], b[N], c[N], siz0[N], siz1[N], n; LL dp[20001][41][41]; inline LL Calc(int u,int x,int y) { // 从根到u的路径上,表示翻新了x条公路,y条铁路 if (u >= n) return 1ll * c[u] * (siz0[u] - x + a[u]) * (siz1[u] - y + b[u]); return dp[u][x][y]; } void dfs(int u) { if (u >= n) { return ; // for (int i = 0; i <= siz0[u]; ++i) // for (int j = 0; j <= siz1[u]; ++j) // dp[u][i][j] = 1ll * c[u] * (siz0[u] - i + a[u]) * (siz1[u] - j + b[u]); // 表示翻新了i条公路,j条铁路 // return ; } siz0[ls[u]] = siz0[u] + 1; siz1[ls[u]] = siz1[u]; dfs(ls[u]); siz0[rs[u]] = siz0[u]; siz1[rs[u]] = siz1[u] + 1; dfs(rs[u]); for (int i = 0; i <= siz0[u]; ++i) for (int j = 0; j <= siz1[u]; ++j) { dp[u][i][j] = 1e18; dp[u][i][j] = min(dp[u][i][j], Calc(ls[u], i + 1, j) + Calc(rs[u], i, j)); // 翻新公路 dp[u][i][j] = min(dp[u][i][j], Calc(ls[u], i, j) + Calc(rs[u], i, j + 1)); // 翻新铁路 } } 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; ls[i] = u; rs[i] = v; } for (int i = 1; i <= n; ++i) a[i + n - 1] = read(), b[i + n - 1] = read(), c[i + n - 1] = read(); dfs(1); cout << dp[1][0][0]; return 0; }