poj2152 Fire(树形DP)

时间:2019-08-27
本文章向大家介绍poj2152 Fire(树形DP),主要包括poj2152 Fire(树形DP)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目链接:https://vjudge.net/problem/POJ-2152

题意:给定一颗大小为n的树,在每个结点建消防站花费为w[i],如果某结点没有消防站,只要在它距离<=d[i]的结点有消防站即可,求最小花费。

思路:

  好难的树形dp,一点思绪也木有,只能搜题解。

  用dp[u][i]表示以u为根的子树满足条件,并且结点u依赖于结点i的最小花费。用best[u]表示以u根的子树满足条件的最小花费,那么best[u]=min(dp[u][i])。

  求best[u]时,先跑一遍dfs得到所有结点距离u的距离dis[i]。如果dis[i]>d[u],那么u没法依赖i,此时dp[u][i]=inf。否则dis[i]<=d[u],此时dp[u][i]=w[i]+sum( min( best[v] , dp[v][i]-w[i] ) ),其中i从1遍历到n,v是u的子结点。因为v的依赖有两种情况,如果v依赖于以v为根的子树中的结点,即best[v]; 如果v依赖于其余的结点,那么一定是i。反证一下,如果v依赖于k,那么u也一定依赖于k。所以应取best[v]和dp[v][i]-w[i]的最小值,减w[i]是因为w[i]多加了一次。

AC代码:

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn=1e3+5;
const int inf=0x3f3f3f3f;
int T,n,cnt,head[maxn],w[maxn],d[maxn],dp[maxn][maxn],dis[maxn];
int best[maxn];

struct node{
    int v,w,nex;
}edge[maxn<<1];

void adde(int u,int v,int w){
    edge[++cnt].v=v;
    edge[cnt].w=w;
    edge[cnt].nex=head[u];
    head[u]=cnt;
}

void getdis(int u,int fa,int len){
    dis[u]=len;
    for(int i=head[u];i;i=edge[i].nex){
        int v=edge[i].v;
        if(v==fa) continue;
        getdis(v,u,len+edge[i].w);
    }
}

void dfs(int u,int fa){
    for(int i=head[u];i;i=edge[i].nex){
        int v=edge[i].v;
        if(v==fa) continue;
        dfs(v,u);
    }
    getdis(u,0,0);
    best[u]=inf;
    for(int i=1;i<=n;++i){
        if(dis[i]>d[u]) dp[u][i]=inf;
        else{
            dp[u][i]=w[i];
            for(int j=head[u];j;j=edge[j].nex){
                int v=edge[j].v;
                if(v==fa) continue;
                dp[u][i]+=min(best[v],dp[v][i]-w[i]);
            }
        }
        best[u]=min(best[u],dp[u][i]);
    }
}

int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        cnt=0;
        for(int i=1;i<=n;++i)
            head[i]=0;
        for(int i=1;i<=n;++i)
            scanf("%d",&w[i]);
        for(int i=1;i<=n;++i)
            scanf("%d",&d[i]);
        for(int i=1;i<n;++i){
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            adde(u,v,w);
            adde(v,u,w);
        }
        dfs(1,0);
        printf("%d\n",best[1]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/FrankChen831X/p/11419331.html