5290: [Hnoi2018]道路

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;
}

 

posted @ 2019-02-23 22:07  MJT12044  阅读(155)  评论(0编辑  收藏  举报