【树形DP】POJ 2152 Fire

通道:http://poj.org/problem?id=2152

题意:n个城市,建防火站,花费w[i],如果这个城市没有防火站,则最近的不超过d[i],求最小花费

思路:

设dp[i][j]表示i点及其子树都符合情况下i点依赖j点的最小花费,有了这个似乎还不够,再开个一维数组best,best[i]表示以i为根的子树符合题目要求的最小花费。这样状态转移方程就是dp[i][j] = cost[j] + sum(min(dp[k][j]-cost[j],best[k])) (k为i的子节点,j为我们枚举的n个点),因为i的每个子节点可以和i一样依赖j结点,那么花费是dp[k][j]-cost[j],或者依赖以k为根的树中的某点,花费是best[k],最后再加上cost[j]

代码:

#include <cstdio>  
#include <cstring>  
#include <algorithm>  
#define N 1010  
#define inf 0x3f3f3f3f  
using namespace std;  
  
int n,cost[N],limit[N],tim[N],dep,son[N];  
int dis[N][N];  
int dp[N][N],best[N];  
int head[N],cnt;  
struct Edge{  
    int v,w,next;  
}edge[N*2];  
  
void init(){  
    memset(head,-1,sizeof(head));  
    memset(tim,0,sizeof(tim));  
    cnt=dep=0;  
}  
  
void addedge(int u,int v,int w){  
    edge[cnt].v=v;  
    edge[cnt].w=w;  
    edge[cnt].next=head[u];  
    head[u]=cnt++;  
    edge[cnt].v=u;  
    edge[cnt].w=w;  
    edge[cnt].next=head[v];  
    head[v]=cnt++;  
}  
  
void init_dfs(int u,int fa){  
    tim[u]=++dep;  
    son[u]=1;  
    for(int i=head[u];i!=-1;i=edge[i].next){  
        int v=edge[i].v;  
        if(v==fa)continue;  
        init_dfs(v,u);  
        son[u]+=son[v];  
    }  
}  
  
void cal_dis(int u,int fa,int now){  
    for(int i=head[u];i!=-1;i=edge[i].next){  
        int v=edge[i].v;  
        if(v==fa)continue;  
        dis[now][v]=dis[now][u]+edge[i].w;  
        cal_dis(v,u,now);  
    }  
}  
  
void dfs(int u,int fa){  
    for(int i=head[u];i!=-1;i=edge[i].next){  
        int v=edge[i].v;  
        if(v==fa) continue;  
        dfs(v,u);  
    }  
    best[u]=inf;  
    for(int j=0;j<n;j++){  
        if(dis[u][j]<=limit[u]){  
            dp[u][j]=cost[j];  
            for(int i=head[u];i!=-1;i=edge[i].next){  
                int v=edge[i].v;  
                if(v==fa) continue;  
                dp[u][j]+=min(best[v],dp[v][j]-cost[j]);   
            }  
            if(tim[j]>=tim[u] && tim[j]<=tim[u]+son[u]-1)  
                best[u]=min(best[u],dp[u][j]);  
        }  
        else dp[u][j]=inf;  
    }  
}  
  
int main(){  
    int T;  
    scanf("%d",&T);  
    for(int t=0;t<T;t++){  
        init();  
        scanf("%d",&n);  
        for(int i=0;i<n;i++) scanf("%d",&cost[i]);  
        for(int i=0;i<n;i++) scanf("%d",&limit[i]);  
        for(int i=0;i<n-1;i++){  
            int u,v,w;  
            scanf("%d %d %d",&u,&v,&w);  
            u--;v--;  
            addedge(u,v,w);  
        }  
        init_dfs(0,-1);  
        for(int i=0;i<n;i++){  
            dis[i][i]=0;  
            cal_dis(i,-1,i);  
        }  
        dfs(0,-1);  
        printf("%d\n",best[0]);  
    }  
}  
View Code

 

posted @ 2014-11-03 19:27  mithrilhan  阅读(163)  评论(0编辑  收藏  举报