• POJ2152 Fire (树形DP)


    题意:n个城市n-1条边 组成一棵树 在每个城市修建消防站会有一个花费costi

           每个城市能防火当且仅当地图上距离他最近的消防站距离小于di

        问如何修建消防站 使地图上所有的城市都有预防火灾的能力

    题解: 这个题太难了..... 完全不会

            具体来说就是用dp[i][j]表示在处理i这个城市的时候在j城市修消防站

            如果dis i,j > di 那么表示这样修不合法就让dp[i][j] = INF

            如果合法这样就已经确定了两个状态

            那么我们同样采用先递归再回溯更新的方法 用ans[i]表示包含i的这棵子树已经处理好的最小值

            那么回溯时肯定是由他的儿子转移过来

            可以直接更新 dp[i][j] += ans[v] 最后dp[i][j] += costj

            但可能有一种重复的情况 即j这个消防站既能保护i也能v 

            所以这种情况就是dp[i][j] += dp[v][j] - costj 减去重复计算的花费

            最后再更新ans[i] = min(dp[i][j])j从1 - n

    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string.h>
    using namespace std;
    const int INF = 2000000009;
    
    int n;
    int cost[1005];
    int d[1005];
    int dis[1005];
    int head[1005];
    int ans[1005];
    int dp[1005][1005];
    
    struct node
    {
        int to, nex, val;
    }E[2005];
    
    void dfs1(int x, int fa)
    {
        int c = head[x];
        for(int i = c; i; i = E[i].nex)
        {
            int v = E[i].to;
            if(v == fa) continue;
            dis[v] = dis[x] + E[i].val;
            dfs1(v, x);
        }
    }
    
    void dfs2(int x, int fa)
    {
        int c = head[x];
        for(int i = c; i; i = E[i].nex)
        {
            int v = E[i].to;
            if(v == fa) continue;
            dfs2(v, x);
        }
    
        dis[x] = 0;
        dfs1(x, -1);
    
        for(int i = 1; i <= n; i++)
        {
            if(dis[i] > d[x])
            {
                dp[x][i] = INF;
                continue;
            }
    
            for(int j = c; j; j = E[j].nex)
            {
                int vv = E[j].to;
                if(vv == fa) continue;
    
                dp[x][i] += min(ans[vv], dp[vv][i] - cost[i]);
            }
            dp[x][i] += cost[i];
        }
        for(int i = 1; i <= n; i++) ans[x] = min(ans[x], dp[x][i]);
    }
    
    int main()
    {
        int T;
        scanf("%d", &T);
        while(T--)
        {
            memset(dp, 0, sizeof(dp));
            memset(ans, 63, sizeof(ans));
            memset(head, 0, sizeof(head));
            int cnt = 0;
            scanf("%d", &n);
            for(int i = 1; i <= n; i++) scanf("%d", &cost[i]);
            for(int i = 1; i <= n; i++) scanf("%d", &d[i]);
    
            for(int i = 1; i < n; i++)
            {
                int u, v, o; scanf("%d%d%d", &u, &v, &o);
                E[++cnt].to = v; E[cnt].nex = head[u]; head[u] = cnt; E[cnt].val = o;
                E[++cnt].to = u; E[cnt].nex = head[v]; head[v] = cnt; E[cnt].val = o;
            }
    
            dfs2(1, -1);
            printf("%d
    ", ans[1]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Vue3源码系列之触发更新的实现
    Vue3源码系列之依赖收集的实现
    Vue3源码系列之reactiveApi实现
    删除链表的倒数第n个节点
    Shared_ptr 参考实现
    linux 目录结构 比较老
    C++11 bind function
    状态机DP
    尾递归
    秒杀系统的构建(2)
  • 原文地址:https://www.cnblogs.com/lwqq3/p/9082601.html
Copyright © 2020-2023  润新知