poj 2152 Fire (树形DP难题)

题目链接;https://vjudge.net/contest/246776#problem/C

题目大意:有n个城市,每两个城市只有一条路连接,(所以可以当成是一颗树)。现在要建设一些防火站,使每个城市都可以被覆盖。每个城市的属性是:在本城市建防火站的价钱和不在本城市建设的话,所依赖的别的防火站的最长距离。然后是n-1条路,和这条路的长度。现在问在覆盖所有城市的前提下的最少价格。

题目思路:

  dp[i][j]:表示以i为根的子树里修建一些消防站,并在节点j处修建一消防站,i的负责站必须是j;

    best[i]:表示表示以i为根的子树的所有节点都有负责站的最小花费。

    dist[i]:表示i到x的距离(每换换一个节点,都要再求一次dist[])。

    状态状态转移方程:dp[i][j]=w[j]+sum(min(best[y],dp[y][j]-w[j]))(y是i的所有孩子,除了父节点);

解释:对于结点i,如果它使用j结点的防火站。那么对于他的孩子的子树而言,要么加上该孩子v的以v为根的子树的所有节点都有负责站的最小花费,即best【v】,要么加上dp[y][j],同样是以j为防火站,因为此时i已经加上了j防火站建造的费用,所以dp【y】【j】可以减去w【j】的费用。两者取个小的加上即可。

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
using namespace std;
const int maxn=1010;
const int inf=1<<30;
struct City
{
    int d,w;

}city[maxn];
struct edge
{
    int child,d;
    edge(int x,int y)
    {
        child=x;
        d=y;
    }
};
vector <edge>tree[maxn];
int n,dis[maxn],best[maxn],dp[maxn][maxn];
void init()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)tree[i].clear();
    for(int i=1;i<=n;i++)scanf("%d",&city[i].w);
    for(int i=1;i<=n;i++)scanf("%d",&city[i].d);
    for(int i=1;i<n;i++)
    {
        int l,r,c;
        scanf("%d%d%d",&l,&r,&c);
        tree[l].push_back(edge(r,c));
        tree[r].push_back(edge(l,c));
    }
}
void getdis(int key)
{
    int len=tree[key].size();
    for(int i=0;i<len;i++)
    {
        int v=tree[key][i].child;
        if(dis[v]!=-1)continue;
        dis[v]=dis[key]+tree[key][i].d;
        getdis(v);
    }
}
void dfs(int key,int parent)
{
    int len=tree[key].size();
    for(int i=0;i<len;i++)
    {
        int v=tree[key][i].child;
        if(v!=parent)
            dfs(v,key);
    }
    memset(dis,-1,sizeof dis);
    best[key]=inf;dis[key]=0;
    getdis(key);
    for(int i=1;i<=n;i++)
    {
        if(dis[i]>city[key].d)dp[key][i]=inf;
        else
        {
            dp[key][i]=city[i].w;
            for(int j=0;j<len;j++)
            {
                int v=tree[key][j].child;
                if(v==parent)continue;
                dp[key][i]+=min(best[v],dp[v][i]-city[i].w);
            }
            best[key]=min(dp[key][i],best[key]);
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        init();
        dfs(1,0);
        printf("%d\n",best[1]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36782366/article/details/81671346