【poj2152】Fire 树形DP

来源:互联网 发布:听音识曲哪个软件更好 编辑:程序博客网 时间:2024/05/20 05:56

Description

Country Z has N cities, which are numbered from 1 to N. Cities are connected by highways, and there is exact one path between two different cities. Recently country Z often caught fire, so the government decided to build some firehouses in some cities. Build a firehouse in city K cost W(K). W for different cities may be different. If there is not firehouse in city K, the distance between it and the nearest city which has a firehouse, can’t be more than D(K). D for different cities also may be different. To save money, the government wants you to calculate the minimum cost to build firehouses.

Input

The first line of input contains a single integer T representing the number of test cases. The following T blocks each represents a test case.

The first line of each block contains an integer N (1 < N <= 1000). The second line contains N numbers separated by one or more blanks. The I-th number means W(I) (0 < W(I) <= 10000). The third line contains N numbers separated by one or more blanks. The I-th number means D(I) (0 <= D(I) <= 10000). The following N-1 lines each contains three integers u, v, L (1 <= u, v <= N,0 < L <= 1000), which means there is a highway between city u and v of length L.

Output

For each test case output the minimum cost on a single line.

Sample Input

551 1 1 1 11 1 1 1 11 2 12 3 13 4 14 5 151 1 1 1 12 1 1 1 21 2 12 3 13 4 14 5 151 1 3 1 12 1 1 1 21 2 12 3 13 4 14 5 142 1 1 13 4 3 21 2 31 3 31 4 244 1 1 13 4 3 21 2 31 3 31 4 2

Sample Output

21223

Source

POJ Monthly,Lou Tiancheng


题意:给你一颗树,边上权值表示距离,一个点上可以建消防站,花费为costi,一个节点要么建消防站,要么周围di距离内必须有一个消防站,求覆盖全图的最小花费。

神一般的解法

ans[u]为u的子树的答案,dp[u][v]表示u节点被v保护的答案,dist[u][v]表示u到v的距离。

因为d[i]不为负,所以可以看看v保护u时是否可以保护u的儿子,以此来更新。

具体来说就是若v可以保护u,则dp[u][v]=cost[v]+min(dp[k][v]cost[v],ans[k]),其中k是u的儿子。具体来说就是先选上v,然后若v能保护k,则取min,减去cost[v]是因为在计算k的时候算了一遍,所以要剪掉防止重复。

若v不可以保护u,则dp[u][v]=INF。

算完之后,ans[u]=min{dp[u][i]}

要先递归,回溯的时候计算…

#include<cstdio>#include<cstring>#include<algorithm>#include<iostream>#include<queue>using namespace std;const int INF = 1000000010;const int SZ = 2010;int cost[SZ],d[SZ],n;int dist[SZ][SZ];int head[SZ],nxt[SZ],tot = 1;struct edge{    int t,d;}l[SZ];void build(int f,int t,int d){    l[++ tot].t = t;    l[tot].d = d;    nxt[tot] = head[f];    head[f] = tot;}queue<int> q;void getdist(int dist[],int s){    dist[s] = 0;    q.push(s);    while(q.size())    {        int u = q.front(); q.pop();        for(int i = head[u];i;i = nxt[i])        {            int v = l[i].t;            if(!dist[v] && v != s)                dist[v] = dist[u] + l[i].d,q.push(v);        }    }}int dp[SZ][SZ],ans[SZ];void dfs(int u,int fa){    for(int i = head[u];i;i = nxt[i])    {        int v = l[i].t;        if(v == fa) continue;        dfs(v,u);    }       for(int v = 1;v <= n;v ++)    {        if(dist[u][v] <= d[u])        {            int tmp = 0;            for(int i = head[u];i;i = nxt[i])            {                int k = l[i].t;                if(k == fa) continue;                tmp += min(dp[k][v] - cost[v],ans[k]);            }            dp[u][v] = cost[v] + tmp;        }        else            dp[u][v] = INF;    }    for(int i = 1;i <= n;i ++)        ans[u] = min(ans[u],dp[u][i]);}void init(){    tot = 1;    memset(head,0,sizeof(head));    memset(dp,0,sizeof(dp));    memset(dist,0,sizeof(dist));    memset(ans,63,sizeof(ans));}int main(){    int T;    scanf("%d",&T);    while(T --)    {        init();        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 - 1;i ++)        {            int a,b,c;            scanf("%d%d%d",&a,&b,&c);            build(a,b,c); build(b,a,c);        }        for(int i = 1;i <= n;i ++)            getdist(dist[i],i);        dfs(1,0);        printf("%d\n",ans[1]);    }    return 0;}
0 0
原创粉丝点击