算法:poj 4045 Power Station (树形dp)

题意

n个城市节点构成的一棵树,节点i到节点j的电量损耗为 I*I*R*(i到j的路径所含边数),现 在要在某个结点上修建一个供电站,使得这个结点到所有其它节点的总损耗量最小。

思路

典型的树形dp

可以先用一次dfs求出每一点的子树结点个数num[u],以及每一点到它子树所有结点的总 距离f[u][0];

然后再用一次dfs,推出每个结点到除去它子树部分的结点总距离f[u][1]。

f[v][1] = (f[u][0]-f[v][0]-num[v]) + f[u][1] + n - num[v];

代码

/**==========================================
* This is a solution for ACM/ICPC problem
*
* @source: poj-4045 Power Station
* @type: 树形dp
* @author: shuangde
* @blog: blog.csdn.net/shuangde800
* @email: zengshuangde@gmail.com
*===========================================*/
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
using namespace std;

typedef long long int64;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const int MAXN = 50010;

int64 f[MAXN][2];
int64 num[MAXN], ans;
bool vis[MAXN];
int n, I, R;
vector<int>adj[MAXN];

int64 dfs(int u){
vis[u] = true;
// u为根节点的子树,方向往下,u到所有子节点的总距离
f[u][0] = 0;

// u为根节点的子树,方向往下,共有多少个结点
num[u] = 1;

for(int i=0; i<adj[u].size(); ++i){
int v = adj[u][i];
if(vis[v]) continue;
dfs(v);
f[u][0] += f[v][0];
num[u] += num[v];
}
f[u][0] += num[u]-1;
return f[u][0];
}

void dp(int u){
vis[u] = true;
for(int i=0; i<adj[u].size(); ++i){
int v = adj[u][i];
if(vis[v]) continue;
// 计算出以v为根节点,方向往上, 总距离
// http://www.bianceng.cn
f[v][1] = (f[u][0]-f[v][0]-num[v]) + f[u][1] + n - num[v];
dp(v);
}
ans = min(ans, f[u][0]+f[u][1]);
}

int main(){

int nCase;
scanf("%d", &nCase);
while(nCase--){
scanf("%d%d%d", &n, &I, &R);

for(int i=0; i<=n; ++i) adj[i].clear();

for(int i=0, u, v; i<n-1; ++i){
scanf("%d%d", &u, &v);
adj[u].push_back(v);
adj[v].push_back(u);
}

memset(vis, 0, sizeof(vis));
dfs(1);

ans = (int64)1<<62;
memset(vis, 0, sizeof(vis));
f[1][1] = 0;
dp(1);

cout << ans*I*I*R<< endl;

bool first = true;
for(int i=1; i<=n; ++i){
if(f[i][0]+f[i][1] == ans){
if(first){first=false; printf("%d", i);}
else printf(" %d", i);
}
}
printf("\n\n");
}

return 0;
}

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索int
, include
, 结点
, 节点
, num
, 树形
acm poj
树形dp、树形dp入门、bzoj 树形dp、poj树形dp、树形dp专题,以便于您获取更多的相关知识。

时间: 2025-01-01 03:15:55

算法:poj 4045 Power Station (树形dp)的相关文章

算法:poj 3107 Godfather(树形dp)

题意 给一颗n个结点的树,节点编号为1~n,问删除一个节点之后,让剩下的分支中节点数量最多的尽 量少. 可能有多种方案,按编号顺序输出. 思路 简单的树形dp. 其实连dp都不能算吧...就是直接 计数统计 先dfs计算每个节点子树的节点个数tot[i]. 再次dfs更新答案: f[i] = max( n-tot[i], max{tot[v] | v是i的儿子} ); 两个dfs可以合并在一个dfs里完成, 复杂度O(n) 代码 /**==============================

算法:ural 1018 Binary Apple Tree(树形dp | 经典)

题意 给一棵边有权值的二叉树,节点编号为1-n,1是根节点.求砍掉一些边,只保留q条边,这q条边 构成的子树 的根节点要求是1,问这颗子树的最大权值是多少? 思路 非常经典的一道树形dp题 ,根据我目前做过的题来看,有多道都是由这题衍生出来的. f(i, j) 表示子树i,保留j个节点(注意是 节点)的最大权值.每条边的权值,把它看作是连接的两个节点中的儿子节点的权值. 那么,就可以对所 有i的子树做分组背包,即每个子树可以选择1,2,...j-1条边分配给它. 状态转移为: f(i, j) =

算法:poj 1155 TELE (树形背包dp)

题意 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结 构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点. 从 转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号 的费用总和. 现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪 些用户提供信号而不给哪些用户提供信号. 写一个程序找出一个方案使得有线电视网在不亏本的情况 下使观看转播的用户尽可能多. 思路 树形

算法:poj 3345 Bribing FIPA (树形背包dp | 输入坑)

题意 有n个国家,你要获取m个国家的支持,获取第i个国家的支持就要给cost[i]的价钱 其中有 一些国家是老大和小弟的关系,也就是说,如果你获得了某个老大国家的支持, 那么这个国家的所有小弟 (包括小弟的小弟...递归下去)都会无偿免费支持你. 问最少的花费可以得到m个国家的支持 思路 这题还是比较好想的树形dp, 不过输入有些麻烦, 一开始以为每组样例结束都是'#',结果一直 RE,后来发现最后一组才是 '#'... 国家由于是直接给名字的,所以我用map<string, int>来映射保

算法:poj 2378 Tree Cutting(树形dp)

题意 给一颗n个结点的树,节点编号为1~n,把删除一个节点之后, 剩下的分支中节点数量最多的数 量不大于总数量一半的编号全部按顺序输出 思路 和poj-3107 GodFather完全一样,只是输出不一样. 改为<=n/2的就输出即可. 代码 /**===================================================== * This is a solution for ACM/ICPC problem * * @source : poj-2378 Tree C

算法:poj 1947 Rebuilding Roads (树形背包dp)

题意 给一棵树,问最少删掉几条边.使得剩下的子树中有节点个数为p个的 思路 几天前就看了 这题, 但是没什么想法,之后每天都有去想一下, 直到今天, 在我对自己方法还有怀疑 的情况下,竟然AC了 .. f(i, j) 表示子树i,保留j个节点的最少删边次数, 注意,这里保留的j个节点的子树,是指根节点 为i的且有j个节点的子树.这样理解的话, 状态转移就容易想多了. 对于子树i, 如果只保留1个节 点,那么连接它所有儿子节点的边都要删掉, 所以可以初始化 f(i, 1) = 节点i的儿子个数 f

算法:poj 3140 Contestants Division(树形dp? dfs计数+枚举)

题目 给n个节点的带权树,删掉其中一边,就会变成两颗子树, 求删去某条边使得这这两颗子树的 权值之差的绝对值最小. 思路 直接dfs一次,计算所有子树的权值总和tot[i] 如果删掉一条边 (v, fa),fa是v的父亲节点, 那么v子树权值总和为tot[v],显然另一棵子树的权值总和就是sum-tot[v] , 最总取最小绝对值即可. 这题要注意用long long 其实就是dfs+枚举,想不通为什么有人会 把这题列为树形dp? 代码 /**==========================

算法:poj 1655 Balancing Act(树形dp)

题意 一n个节点的棵树,去掉某个节点后,会变成一个森林. 这个森林中的每个树都有个节点数量, 其中最大节点数设为max 问删除某个节点后,max最小可以多少? 思路 和poj-3107 GodFather完全一样! 不想吐槽了... 其实本来不想发这篇,不过发现今天是八月最后一天,而且 还差一篇就发了80篇了..于是..就很邪恶的水了 代码 /**===================================================== * This is a solution

算法:uva 1407 Caves (树形背包dp)

题意 一棵n个节点的树,树的边有正整数权,表示两个节点之间的距离.你的任务是回答这样的询问:从跟 节点出发,走不超过x单位的距离, 最多能经过多少节点?同一个节点经过多次, 只能算一个. 思路 这题同样是多天前看的, 在今天才想出解法的. 动态规划就是这么有意思 :) 遍历n个节点, 有两种情 况, 第一种是遍历完之后不回到出发点, 第二种是要回到出发点. 两种都可能会重复经过某些边, 但是显 然还是第二种遍历的花费会更大 在这一题中, 遍历之后不需要回到出发点. f(i, j, 0): 表示遍