POJ2152 Fire

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

题意

树型DP

数据范围较小,首先,暴力求出两点间距离

\(f[i]\)表示以\(i\)为根的子树全部被消防站覆盖的最小花费,\(g[i][j]\)表示以\(i\)为根的子树全部被消防站覆盖,且\(u\)使用\(i\)的消防站的最小花费

\[f[u]=\min_{1\le i \le n} g[u][i]\\ g[u][i]=w[i]+\min_{v是u的儿子} (g[v][i]-w[i],f[v])\\ g[v][i]-w[i]:v也从属于i,那么i站被建了两次,需要减去重复部分\\ \min_{v是u的儿子} (g[v][i]-w[i],f[v])保证了u的子节点被完全覆盖,\\ 同时u也被覆盖了,从而保证了以u为根的子树全部被消防站覆盖 \]

\(C++ Code:\)

#include<cstdio>
#include<iostream>
#include<cstring>
#define INF 1000000009
#define N 2005
#define RN 1005
using namespace std;
int T,x,y,z,n,rt,tot,head[RN],nxt[N],d1[N],d2[N],f[RN],g[RN][RN],dis[RN][RN],w[RN],d[RN];
void Clear()
{
    for (int i=0;i<=RN;f[i]=INF,i++)
        for (int j=0;j<=RN;j++)
            g[i][j]=INF;
    memset(head,0,sizeof head);
    tot=0;
}
void add(int x,int y,int z)
{
    tot++;
    d1[tot]=y,d2[tot]=z;
    nxt[tot]=head[x],head[x]=tot;
}
void dfs(int u,int f)
{
    for (int i=head[u];i;i=nxt[i])
    {
        int v=d1[i];
        int cost=d2[i];
        if (v==f)
            continue;
        dis[rt][v]=dis[rt][u]+cost;
        dfs(v,u);
    }
}
void tree_dp(int u,int F)
{
    for (int i=1;i<=n;i++)
        if (dis[u][i]<=d[u])
            g[u][i]=w[i]; else
            g[u][i]=INF;
    for (int i=head[u];i;i=nxt[i])
    {
        int v=d1[i];
        if (v==F)
            continue;
        tree_dp(v,u);
    }
    for (int i=head[u];i;i=nxt[i])
    {
        int v=d1[i];
        if (v==F)
            continue;
        for (int i=1;i<=n;i++)
            if (dis[u][i]<=d[u])
                g[u][i]+=min(f[v],g[v][i]-w[i]);
    }
    for (int i=1;i<=n;i++)
        f[u]=min(f[u],g[u][i]);
}
int main()
{
    scanf("%d",&T);
    while (T --> 0)
    {
        Clear();
        scanf("%d",&n);
        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++)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        for (int i=1;i<=n;i++)
        {
            dis[i][i]=0;
            rt=i;
            dfs(i,0);
        }
        tree_dp(1,0);
        cout << f[1] << endl;
    }
}
posted @ 2020-07-24 15:38  GK0328  阅读(92)  评论(0编辑  收藏  举报