水库(树形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\n", best[1]);
    return 0;
}

转载于:https://www.cnblogs.com/MyNameIsPc/p/7738471.html

源码地址: https://pan.quark.cn/s/d1f41682e390 miyoubiAuto 米游社每日米游币自动化Python脚本(务必使用Python3) 8更新:更换cookie的获取地址 注意:禁止在B站、贴吧、或各大论坛大肆传播! 作者已退游,项目不维护了。 如果有能力的可以pr修复。 小引一波 推荐关注几个非常可爱有趣的女孩! 欢迎B站搜索: @嘉然今天吃什么 @向晚大魔王 @乃琳Queen @贝拉kira 第三方库 食用方法 下载源码 在Global.py中设置米游社Cookie 运行myb.py 本地第一次运行时会自动生产一个文件储存cookie,请勿删除 当前仅支持单个账号! 获取Cookie方法 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 按刷新页面,按下图复制 Cookie: How to get mys cookie 当触发时,可尝试按关闭,然后再次刷新页面,最后复制 Cookie。 也可以使用另一种方法: 复制代码 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 控制台粘贴代码并运行,获得类似的输出信息 部分即为所需复制的 Cookie,点击确定复制 部署方法--腾讯云函数版(推荐! ) 下载项目源码和压缩包 进入项目文件夹打开命令行执行以下命令 xxxxxxx为通过上面方式或取得米游社cookie 一定要用双引号包裹!! 例如: png 复制返回内容(包括括号) 例如: QQ截图20210505031552.png 登录腾讯云函数官网 选择函数服务-新建-自定义创建 函数名称随意-地区随意-运行环境Python3....
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值