• [HNOI/AHOI2018]道路


    Description:

    W 国的交通呈一棵树的形状。W 国一共有(n - 1)个城市和(n)个乡村,其中城市从(1)(n - 1) 编号,乡村从(1)(n)编号,且(1)号城市是首都。道路都是单向的,本题中我们只考虑从乡村通往首都的道路网络。对于每一个城市,恰有一条公路和一条铁路通向这座城市。对于城市i, 通向该城市的道路(公路或铁路)的起点,要么是一个乡村,要么是一个编号比(i)大的城市。 没有道路通向任何乡村。除了首都以外,从任何城市或乡村出发只有一条道路;首都没有往 外的道路。从任何乡村出发,沿着唯一往外的道路走,总可以到达首都。
    W 国的国王小 W 获得了一笔资金,他决定用这笔资金来改善交通。由于资金有限,小 W 只能翻修(n - 1)条道路。小 W 决定对每个城市翻修恰好一条通向它的道路,即从公路和铁 路中选择一条并进行翻修。小 W 希望从乡村通向城市可以尽可能地便利,于是根据人口调 查的数据,小 W 对每个乡村制定了三个参数,编号为(i)的乡村的三个参数是(a_i)(b_i)(c_i)。假设 从编号为(i)的乡村走到首都一共需要经过(x)条未翻修的公路与(y)条未翻修的铁路,那么该乡村 的不便利值为

    [c_i cdot (a_i + x) cdot (b_i + y) ]

    在给定的翻修方案下,每个乡村的不便利值相加的和为该翻修方案的不便利值。 翻修(n - 1)条道路有很多方案,其中不便利值最小的方案称为最优翻修方案,小 W 自然 希望找到最优翻修方案,请你帮助他求出这个最优翻修方案的不便利值。

    Hint:

    对于所有的数据,(n le 20000)(1 le a_i,b_i le 60)(1 le c_i le 10^9)(s_i,t_i)([-n,-1] cup (i,n - 1])内的整数,任意乡村可以通过不超过40条道路到达首都。

    Solution:

    表面上不可做实际上并不难的树型dp
    (f[i][j][k]) 表示在i节点,到根修了j条公路,k条铁路的代价
    显然有转移:
    (f[i][j][k]=min(f[ls][j+1][k]+f[rs][j][k],f[ls][j][k],f[rs][j][k+1]))
    可以考虑直接出叶子节点的f值,然后由根的初始状态出发(f[1][0][0]),记忆化搜索
    但是这题卡空间,但是树的最大深度为40,我们发现一个点只由儿子转移过来,所以只需开一条链的空间大小,详见代码:

    #include <map>
    #include <set>
    #include <stack>
    #include <cmath>
    #include <queue>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #define ls p<<1 
    #define rs p<<1|1
    using namespace std;
    typedef long long ll;
    const int mxn=4e4+5;
    int n,m,a[mxn],b[mxn],c[mxn],to[mxn][2];
    ll f[105][85][85];
    
    inline int read() {
        char c=getchar(); int x=0,f=1;
        while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
        while(c<='9'&&c>='0') {x=(x<<3)+(x<<1)+(c&15);c=getchar();}
        return x*f;
    }
    inline int chkmax(int &x,int y) {if(x<y) x=y;}
    inline int chkmin(int &x,int y) {if(x>y) x=y;}
    
    struct ed {
        int to,nxt;
    }t[mxn<<1];
    
    void dfs(int u,int id,int x,int y)
    {
        if(to[u][0]) dfs(to[u][0],id+1,x+1,y);
        if(to[u][1]) dfs(to[u][1],id+2,x,y+1);
        if(u>n) {
            for(int i=0;i<=x;++i)
                for(int j=0;j<=y;++j)
                    f[id][i][j]=1ll*c[u]*(a[u]+i)*(b[u]+j);
        }
        else {
            for(int i=0;i<=x;++i) 
                for(int j=0;j<=y;++j)
                    f[id][i][j]=min(f[id+1][i+1][j]+f[id+2][i][j],f[id+1][i][j]+f[id+2][i][j+1]);
        }
    }
    
    int main()
    {
        int u,v;
        n=read(); memset(f,0x3f,sizeof(f));
        for(int i=1;i<n;++i) {
            u=read(); v=read();
            if(u<0) u=-u+n;
            if(v<0) v=-v+n;
            to[i][0]=u; to[i][1]=v;
        }
        for(int i=1;i<=n;++i) 
            a[i+n]=read(),b[i+n]=read(),c[i+n]=read();
        dfs(1,1,0,0);
        printf("%lld",f[1][0][0]);
        return 0;
    }
    
    
  • 相关阅读:
    NYOJ228 士兵杀敌(五)
    NYOJ236 彩色棒 字典树 + 并查集 + 欧拉路
    给大家推荐一个用电脑拨打普通电话的软件skype
    转:甲骨文将以74亿美元收购太阳微系统公司
    花生壳原理求解
    利用IHttpModule及Session_End事件进行在线会员统计遇到的问题
    我的开发环境介绍及一个 Expression Bland 画图形的例子
    WF (Windows Workflow Foundation) 工作流学习(二)一个Asp.Net 与 顺序工作流 结合的例子
    WPF 、WinFrom 调用顺序工作流的登陆窗口例子
    Expression Bland 入门视频(三) 菜单、项目面板及工作区介绍
  • 原文地址:https://www.cnblogs.com/list1/p/10510051.html
Copyright © 2020-2023  润新知