题意:给定一棵n个节点的树,要在某些点上建设消防站,使得所有点都能够通过某个消防站解决消防问题,但是每个点的建站费用不同,能够保证该点安全的消防站的距离上限也不同。给定每个点的建站费用以及最远的消防站距离上限,求保证该树安全的最小花费。

思路:

  要选择部分点来建站解决消防问题,而总花费是有最优解的。

  如何进行树形DP?

  假设某点t的所有子树的消防问题都解决,而且已经获得最优解了,那么现在考虑的是点t的最优解问题,点t可以依靠任何点只要不超过距离限制即可,那枚举一下所有点试试,一旦t依靠某个点j解决消防问题,那么t的孩子/孙子也可能可以依靠j来解决消防问题。这只需要判断一下每个孩子是否能够依靠j就行了,而孙子如果依靠j的话,如何知道?此时,之前已经假设t的孩子的消防问题已经解决,那么t的孩子在枚举依靠站时也肯定枚举过j了,或者能依靠,或者不能依靠。而t的孙子能不能依靠j,是交给t的孩子去解决的,就像t的孩子是交给t来负责一样。这是符合递归性质的,那么当前我们就可以只考虑点t和他的孩子们能不能愉快玩耍就行了。

  但是还有个最优性质,那么在枚举j的基础上,dp[t][j]=w[j]是至少的,然后再加上所有子树的最优花费,就是dp[t][j]了。上面是领会思路的。下面看别人的状态方程。

  复杂度为O(n^2)的树形DP.因为要依赖其他站点,所以不仅仅只从子树中获取信息,也可能从父亲结点,兄弟结点获取信息,所以在计算每个点时首先想到要枚举,因为n特别小,允许我们枚举。设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],因为要在j结点建站所以要增加花费。

  为什么是O(n2)?递归计算每个节点时的复杂度为O(孩子数*n),而每个节点作为孩子节点来计算的话仅有1次。即总复杂度最高为O(n2)。

 //#include <bits/stdc++.h>
#include <vector>
#include <iostream>
#include <cstdio>
#include <cstring>
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int N=; struct node
{
int from,to,len;
node(){};
node(int from,int to,int len):from(from),to(to),len(len){};
}edge[N*];
int edge_cnt, w[N], d[N], n;
vector<int> tree[N];
void add_node(int from,int to,int len)
{
edge[edge_cnt]=node(from,to,len);
tree[from].push_back(edge_cnt++);
} int dist[N][N], root; //到根的距离
void get_dis(int t,int far,int len)
{
dist[root][t]=dist[t][root]=len;
if(len>d[root]) return ;
for(int i=; i<tree[t].size(); i++)
{
node &e=edge[tree[t][i]];
if(e.to!=far) get_dis(e.to,t,len+e.len);
}
} int dp[N][N], best[N];
void DFS(int t,int far)
{
for(int i=; i<tree[t].size(); i++) //递归先解决子问题
{
node &e=edge[tree[t][i]];
if(e.to!=far) DFS(e.to,t);
} best[t]=INF;
for(int j=,sum=; j<=n; j++,sum=) //尝试将i依靠j解决消防问题
{
if( dist[t][j]>d[t] ) continue; //不能依靠到j,太远了
for(int i=; i<tree[t].size(); i++) //每个子节点取最优解
{
node &e=edge[tree[t][i]];
if(e.to!=far) sum+=min(best[e.to], dp[e.to][j]-w[j]);
}
dp[t][j]=w[j]+sum;
best[t]=min(best[t], dp[t][j]);
}
} void init()
{
edge_cnt=;
for(int i=; i<=n; i++) tree[i].clear();
memset(dp, 0x3f, sizeof(dp));
memset(dist, 0x3f, sizeof(dist));
} int main()
{
//freopen("input.txt", "r", stdin);
int t,a,b,c;
cin>>t;
while(t--)
{
scanf("%d",&n);
init();
for(int i=; i<=n; i++) scanf("%d",&w[i]);
for(int i=; i<=n; i++) scanf("%d",&d[i]); //距离i城市最远的消防站距离上限
for(int i=; i<n; i++)
{
scanf("%d%d%d",&a,&b,&c);
add_node(a,b,c);
add_node(b,a,c);
}
for(int i=; i<=n; i++) get_dis(root=i, -, ); //计算任意点对之间的距离
DFS(, -);
printf("%d\n",best[]); }
return ;
}

AC代码

POJ 2152 Fire (树形DP,经典)的更多相关文章

  1. POJ 2152 Fire(树形DP)

    题意: 思路:令F[i][j]表示 的最小费用.Best[i]表示以i为根节点的子树多有节点都找到负责消防站的最小费用. 好难的题... #include<algorithm> #incl ...

  2. POJ 2152 fire / SCU 2977 fire(树型动态规划)

    POJ 2152 fire / SCU 2977 fire(树型动态规划) Description Country Z has N cities, which are numbered from 1 ...

  3. POJ 1155 TELE 背包型树形DP 经典题

    由电视台,中转站,和用户的电视组成的体系刚好是一棵树 n个节点,编号分别为1~n,1是电视台中心,2~n-m是中转站,n-m+1~n是用户,1为root 现在节点1准备转播一场比赛,已知从一个节点传送 ...

  4. HDU 2196 Computer 树形DP 经典题

    给出一棵树,边有权值,求出离每一个节点最远的点的距离 树形DP,经典题 本来这道题是无根树,可以随意选择root, 但是根据输入数据的方式,选择root=1明显可以方便很多. 我们先把边权转化为点权, ...

  5. [POJ 1155] TELE (树形dp)

    题目链接:http://poj.org/problem?id=1155 题目大意:电视台要广播电视节目,要经过中转机构,到观众.从电视台到中转商到观众是一个树形结构,经过一条边需要支付成本.现在给你每 ...

  6. ural 1018 Binary Apple Tree(树形dp | 经典)

    本文出自   http://blog.csdn.net/shuangde800 ------------------------------------------------------------ ...

  7. Apple Tree POJ - 2486 (树形dp)

    题目链接: D - 树形dp  POJ - 2486 题目大意:一颗树,n个点(1-n),n-1条边,每个点上有一个权值,求从1出发,走V步,最多能遍历到的权值 学习网址:https://blog.c ...

  8. Anniversary party POJ - 2342 (树形DP)

    题目链接:  POJ - 2342 题目大意:给你n个人,然后每个人的重要性,以及两个人之间的附属关系,当上属选择的时候,他的下属不能选择,只要是两个人不互相冲突即可.然后问你以最高领导为起始点的关系 ...

  9. POJ 3107.Godfather 树形dp

    Godfather Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7536   Accepted: 2659 Descrip ...

随机推荐

  1. jQuery.ajax各种参数及属性设置

      $.ajax({       type: "post",       url: url,       dataType:'html',       success: funct ...

  2. UVaLive 3635 Pie (二分)

    题意:有f+1个人来分n个圆形派,每个人得到的必须是一个整块,并且是面积一样,问你面积是多少. 析:二分这个面积即可,小了就多余了,多了就不够分,很简单就能判断. 代码如下: #pragma comm ...

  3. HDU - 4006 The kth great number multiset应用(找第k大值)

    The kth great number Xiao Ming and Xiao Bao are playing a simple Numbers game. In a round Xiao Ming ...

  4. LeetCode: 500 Keyboard Row (easy)

    题目: Given a List of words, return the words that can be typed using letters of alphabet on only one ...

  5. 在实战中使用nginx-rtmp遇到的TCP连接问题分析

    在实战中使用nginx-rtmp遇到的TCP连接问题分析 背景 前段时间公司做了一次体育赛事的现场直播,网络由某通信公司负责搭建,主要测试5G CPE上行网络的带宽和稳定性,为了做到万无一失,他们同时 ...

  6. E20190409-hm

    viable  adj. 切实可行的; 能养活的; 能自行生产发育的; 有望实现的; resolution  n. 分辨率; 解决; 决心; 坚决; produce vt. 产生; 生产; 制作; 创 ...

  7. Linux下新建一个站点

    Apache+nagix使用Lnmpa创建一个新的站点 我们在部署服务器的时候通常会遇到需要分域名和分应用部署,那么如何通过Apache+nagix创建一个新的站点服务呢 LNMPA这种架构有什么优势 ...

  8. C#利用WebService接口下载文件

    WebTest.RtTfSimDataInterface test = new WebTest.RtTfSimDataInterface(); //string strBasic = test.Get ...

  9. 基础篇-环境变量 .bash_profile

    千里之行始于足下~~~ PGHOST或者PGHOSTADDR PGPORT PGDATABASE PGUSER PGPASSWORD(不推荐使用这个,推荐使用.pgpass)

  10. JAVA 7新特性——在单个catch代码块中捕获多个异常,以及用升级版的类型检查重新抛出异常

    在Java 7中,catch代码块得到了升级,用以在单个catch块中处理多个异常.如果你要捕获多个异常并且它们包含相似的代码,使用这一特性将会减少代码重复度.下面用一个例子来理解. Java 7之前 ...