poj4045——树形DP

题目链接:

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=28138


题目大意:

有n个小区,有n-1条边将这n个小区连接起来。( 3<=n<=50000)

现在要选择一个小区建设一个电站,小区到电站的电缆是有损耗的。

公式为:I*I*R*Di。

Di表示所有小区到该电站的距离之和,求取最小的损耗。


解题思路:

不能进行暴力枚举,时间复杂度是n^2,会超时。

可以使用树形DP。

建树的方法不一定,看大家自己的喜好。

我定义了3个数组:

Count[i]:i节点的子孙节点的总个数。

dp[i]:      i节点的子孙节点到该节点的距离之和。

dis[i]:     非i节点的子孙节点到i节点的距离之和。

那么最后每个点的距离之和就是: dp[i]+dis[i]。

Count[i]数组的求法:

Count[i]+=(Count[j]+1);

j是i的孩子节点,通过从根节点开始的dfs,从后往前递推,可以很快求出该数组。


dp[i]数组的求法:

dp[i]+=(dp[j]+Count[j]+1);

j是i的孩子节点,通过从根节点开始的dfs,从后往前推,可以很快求出该数组。


dis[i]数组的求法:

dis[j]=dis[i]+(dp[i]-dp[j]-1-Count[j])+(N-1-Count[j]);

j是i的孩子节点,别的子树上的节点想要达到j必须先到达j的父亲节点i。


源代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
const double eps=1e-8;
int N,I,R,root;
struct node
{
    int father;
    vector child;
}c[50005];
LL dp[50005];      //以i为根节点的子树当中到i节点的距离之和
int Count[50005];   //i节点的所有子孙节点的个数
void dfs1(int now)  //求dp数组
{
    int i,j,size,child;
    size=c[now].child.size();
    if(size==0) return;
    for(i=0;i

你可能感兴趣的:(树形DP)