wzj52501_图图的设计

【问题描述】
图图是一个很萌很萌很可爱的好孩纸。
他正在玩一款策略游戏, 地图由 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 个整数, 表示最小代价。
【输入输出样例】

design.in design.out
62
1 2 4 2 3
1 2 4
1 3 4
2 6 2
2 4 100
4 5 2
11

【样例解释】
在城市 1235 建立机场, 代价为 11
【数据范围】

测试数据编号 数据范围 其他限制
1 - 3 1 ≤ n ≤ 10
4 - 5 1 ≤ n ≤ 51
6 - 9 1 ≤ n ≤ 2501 对于所有 1 ≤ i ≤ n - 1v[i] = u[i] + 1
10

对于 100%的数据: 1 ≤ ncost[i]w[i] ≤ 25011 ≤ u[i]v[i] ≤ n。 


树形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();

}
原文地址:https://www.cnblogs.com/ling-zhi/p/11758646.html