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
原文地址:https://www.cnblogs.com/lwqq3/p/9082601.html