1. 程式人生 > 實用技巧 >POJ2152 Fire

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;
    }
}