zoukankan      html  css  js  c++  java
  • 水库(树形dp)

    水库 (树形dp)

    R国有n座城市和n-1条长度为1的双向道路,每条双向道路连接两座城市,城市之间均相互连通。现在你需要维护R国的供水系统。你可以在一些城市修建水库,在第i个城市修建水库需要每年c_i的维护费用。对于没有修建水库的城市,如果离它最近的水库的距离为d,那么需要每年t_i的运输费用来保证该城市的用水需求。保证t_i严格递增。你的任务是计算出每年所需要的最小花费。对于10%的数据,(n<=5)。对于30%的数据,(n<=20)。对于另外40%的数据,(t_i=i)。对于100%的数据,(n<=1000)(c_i,t_i<=100000)

    这可能算是我做的第一道树形dp?i表示以i为根的子树,j表示i的供水依赖于j。k为i的子节点。(dp[i][j]=t[dis[now][j]]+c[j]+sum min(dp[k][j]-c[j],best[k]))。也就是说对于i的子树,要么i和k共用一个水库,要么用的水库不一样。如果是共用水库,说明水库不用重复建,那么建造水库的成本可以省掉。

    但是我在思考过程中发现这样一种情况:水库

    这个情况。。hjq大神说可以证明不存在。因为既然j也选了,t也选了,i一定是哪个更近选哪个。所以i一定不会选j。(被自己蠢哭了)

    #include <cstdio>
    #include <algorithm>
    
    const int maxn=1005, INF=1e9;
    
    class Graph{
    public:
        struct Edge{
            int to, next; Graph *belong;
            void set(int x, int y, Graph *g){
                to=x; next=y; belong=g; }
            Edge& operator ++(){
                return *this=belong->edge[next]; }
            inline int operator *(){ return to; }
        };
        void addedge(int x, int y){
            edge[++cntedge].set(y, fir[x], this);
            fir[x]=cntedge;
        }
        inline Edge& getlink(int x){ return edge[fir[x]]; }
    private:
        int cntedge, fir[maxn];
        Edge edge[maxn*2];
    };
    
    int n, c[maxn], t[maxn];
    int f[maxn][maxn], best[maxn];
    int dis[maxn][maxn];
    Graph g;
    
    void get_dis(int now, int step, int source, int pre){
        dis[now][source]=dis[source][now]=step;
        Graph::Edge e=g.getlink(now);
        for (; *e; ++e) if (*e!=pre)
            get_dis(*e, step+1, source, now);
    }
    
    void dfs(int now, int par){
        Graph::Edge e=g.getlink(now);
        for (int j=1; j<=n; ++j) f[now][j]=t[dis[now][j]]+c[j];
        for (; *e; ++e){
            if (*e!=par) dfs(*e, now);
            else continue;
            for (int j=1; j<=n; ++j)
                f[now][j]+=std::min(f[*e][j]-c[j], best[*e]);
        }
        for (int j=1; j<=n; ++j)
            best[now]=std::min(best[now], f[now][j]);
    }
    
    int main(){
        scanf("%d", &n);
        for (int i=1; i<=n; ++i) scanf("%d", &c[i]);
        for (int i=1; i<=n; ++i) scanf("%d", &t[i]);
        int x, y;
        for (int i=1; i<n; ++i){
            scanf("%d%d", &x, &y);
            g.addedge(x, y); g.addedge(y, x);
        }
        for (int i=1; i<=n; ++i) get_dis(i, 0, i, 0);
        std::fill(best, best+maxn, INF);
        dfs(1, 0);
        printf("%d
    ", best[1]);
        return 0;
    }
    
  • 相关阅读:
    AI图形算法的应用之一:通过图片模板对比发现油田漏油
    基于GPS定位和人脸识别的作业识别管理系统
    windows平板的开发和选型
    windows系统和IE的兼容性问题
    ASP.NET写的一个博客系统
    Android Studio3.2.1升级刨坑记录
    C#怎样链接mysql数据库
    学习进度条博客
    期末总结
    【操作系统】实验四 主存空间的分配和回收
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/7738471.html
Copyright © 2011-2022 走看看