wzj52501_图图的设计

房东的猫 提交于 2019-12-02 18:55:19

【问题描述】
  图图是一个很萌很萌很可爱的好孩纸。
  他正在玩一款策略游戏, 地图由 n 座城市组成, 并由 n - 1 条无向带权边连
  接成树形结构。 为了解决物资补给, 图图需要在这 n 座城市选出若干座城市建
  立机场, 其中在第 i 座城市建立机场的代价是 cost[i]
  建立机场之后, 每座城市得到补给的代价为该城市到最近机场的距离。 而
  图图总共花费的代价即为建立机场的代价与每座城市得到补给的代价之和, 当
  然图图想让这个代价最小。
  这么难的问题图图当然不会做了, 他想让你帮帮他, 你能解决这个问题吗?
【输入】
  第一行包含 1 个正整数 n
  第二行包含 n 个自然数 cost[i], 表示在第 i 座城市建立机场的代价。
  接下来 n - 1 行每行 3 个整数 u[i]v[i]w[i], 表示有一条无向连接了城市
  u[i]v[i], 距离为 w[i]
【输出】
  输出 1 个整数, 表示最小代价。

测试数据在文件栏里


 

树形dp

考试时没想到哎

f[i]][j]表示假设距离i最短的机场设在j时,i及其子树的花费最小值

注意j可以取1-N

#include<iostream>
#include<cstdio>

#define ri register int
#define u int

namespace opt {

    inline u in() {
        u x(0),f(1);
        char s(getchar());
        while(s<'0'||s>'9') {
            if(s=='-') f=-1;
            s=getchar();
        }
        while(s>='0'&&s<='9') {
            x=(x<<1)+(x<<3)+s-'0';
            s=getchar();
        }
        return x*f;
    }

}

using opt::in;

#define NN 2505
#define MM 2505

#include<algorithm>
#include<cmath>

namespace mainstay {

    u cnt,N,dmx,g[NN],mry[NN][NN],fa[NN][15],f[NN][NN],ans(0x7fffffff),v[NN],d[NN],dic[NN],h[NN];

    struct node {
        u to,next,va;
    } a[MM<<1];

    inline void add(const u &x,const u &y,const u &z) {
        a[++cnt].next=h[x],a[cnt].to=y,a[cnt].va=z,h[x]=cnt;
    }

    void dic_dfs(const u &x,const u &prt,const u &len,const u &deep) {
        dic[x]=len,d[x]=deep,dmx=std::max(deep,dmx),fa[x][0]=prt;
        for(ri i(h[x]); i; i=a[i].next) {
            u _y(a[i].to);
            if(_y^prt) {
                dic_dfs(_y,x,len+a[i].va,deep+1);
            }
        }
    }

    u climb(u x,u y) {
        if(d[x]>d[y]) std::swap(x,y);
        u k(std::log(d[y])/std::log(2));
        for(ri i(k); i>=0; --i) {
            if(d[y]-(1<<i)>=d[x]) y=fa[y][i];
        }
        if(x==y) return x;
        for(ri i(k); i>=0; --i) {
            if(fa[x][i]^fa[y][i]) {
                x=fa[x][i],y=fa[y][i];
            }
        }
        return fa[x][0];
    }

    u query(const u &x,const u &y) {
        if(mry[x][y]) return mry[x][y];
        return mry[x][y]=mry[y][x]=(dic[x]+dic[y]-(dic[climb(x,y)]<<1));
    }

    void dp_dfs(const u &x,const u &prt) {
        for(ri j(1); j<=N; ++j) {
            f[x][j]=query(x,j)+v[j];
        }
        for(ri i(h[x]); i; i=a[i].next) {
            u _y(a[i].to);
            if(_y^prt) {
                dp_dfs(_y,x);
                for(ri j(1); j<=N; ++j) {
                    f[x][j]+=std::min(g[_y],f[_y][j]-v[j]);
                }
            }
        }
        g[x]=0x7fffffff;
        for(ri j(1); j<=N; ++j) {
            g[x]=std::min(f[x][j],g[x]);
        }
    }

    inline void solve() {
        N=in();
        for(ri i(1); i<=N; ++i) v[i]=in();
        for(ri i(1); i<N; ++i) {
            u _a(in()),_b(in()),_c(in());
            add(_a,_b,_c),add(_b,_a,_c);
        }
        dic_dfs(1,0,0,1);
        for(ri j(1); (dmx-(1<<j)>=0); ++j) {
            for(ri i(1); i<=N; ++i) {
                if(fa[i][j-1]>=1)
                    fa[i][j]=fa[fa[i][j-1]][j-1];
            }
        }
        dp_dfs(1,0);
        printf("%d",g[1]);
    }

}

int main() {

    //freopen("design.in","r",stdin);
    //freopen("design.out","w",stdout);
    mainstay::solve();

}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!