POJ 2054 Color a Tree (贪心)
$ POJ2054ColoraTree $

$ solution: $
我们先从题中抽取信息,因为每个点的费用和染色的次数有关,所以我们可以很自然的想到先给权值大的节点染色。但是题目还说每个节点染色前它的父亲节点也必须被染色,这就有了很多的后效性。
暂时没有办法贪心,我们就只能再找找性质。博主首先想到的是从叶子节点考虑,叶子节点里权值最小的一定最后染色。但是经过自我hack,这个结论也是错的。举个栗子:5-1-1-1-8,这条链上如果以左边第一个1为根,先染5会更优。
叶子节点我们拿他没办法,所以我们看看树枝,然后我们可以猜一个贪心:对于某一个节点,在它的所有儿子节点中最早被染色的一定是最大的那个。好吧,这个贪心也是错的,每个节点的费用会受到子节点的影响。
那,什么情况下不会有后效性呢?我们可以从全局考虑,找整颗树上权值最大的节点,这个节点一定在它父亲染色后第一个被染色。这个顺序绝不会变(是一个正确的贪心)。但是我们找到这个最大的节点之后又该如何?找第二大的节点?可这个结论还适用吗?
这里我们有一个常用套路,在之前贪心是我们其实就可以想到:对每个点设定一个新的权值。但是这个设新权值的办法在最开始不好用,它要猜。不过我们在想出上面这个贪心后就可以很容易设出来这个权值。因为上面说过了最大的节点一定在它父亲染色后第一个被染色。这,我们不就相当与将两个点合并吗?但是新权值怎么设?我们仔细思考一下就可以知道新权值为新节点所包含节点的权值和除以包含的节点数
然后我们直接按照这个方法贪心,找最大用优先队列,每次合并时计算一下局部答案即可。复杂度 $ O(nlogn) $
$ code: $
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ll long long
#define db double
#define rg register int
using namespace std;
db d[1005];
int n,root,top;
int s[1005];
int fa[1005];
int tot[1005];
int sum[1005];
int ans[1005];
bool use[1005];
struct pi{
db v; int id;
inline bool operator <(const pi &x)const{
return v<x.v;
}
}a[1005];
priority_queue<pi> q;
inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
if(sign)return -res; else return res;
}
inline int get(int x){
if(x==s[x])return x;
return s[x]=get(s[x]);
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
while(~scanf("%d%d",&n,&root)){
if(!n&&!root)break;
for(rg i=1;i<=n;++i){
rg x=qr(); d[i]=a[i].v=x; a[i].id=i; q.push(a[i]); //读入
s[i]=i; tot[i]=1; use[i]=0; sum[i]=ans[i]=x;//预处理
} use[root]=1; //根节点没有父亲,不能合并,所以直接判它已被使用
for(rg i=1;i<n;++i){
rg x=qr(),y=qr(); fa[y]=x; //读入父子关系y
}
for(rg i=1;i<n;++i){ //有且仅有n-1次合并
while(use[q.top().id]||d[q.top().id]!=q.top().v)q.pop();//有一些节点被用过,是无效的
rg x=q.top().id,y=get(fa[x]); q.pop(); //x为儿子,y为父亲
s[x]=y; use[x]=1; ans[y]+=ans[x]+sum[x]*tot[y]; //更新节点信息
tot[y]+=tot[x]; sum[y]+=sum[x]; //更新节点信息
pi z; d[y]=z.v=(db)sum[y]/tot[y]; z.id=y; q.push(z); //合并节点
}printf("%d\n",ans[root]); //根节点的答案才是最终答案
}
return 0;
}
POJ 2054 Color a Tree (贪心)的更多相关文章
- POJ 2054 Color a Tree#贪心(难,好题)
题目链接 代码借鉴此博:http://www.cnblogs.com/vongang/archive/2011/08/19/2146070.html 其中关于max{c[fa]/t[fa]}贪心原则, ...
- POJ 2054 Color a Tree
贪心.... Color a Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: ...
- POJ 2054 Color a Tree解题报告
题干 Bob is very interested in the data structure of a tree. A tree is a directed graph in which a spe ...
- poj 2054 Color a Tree(贪婪)
# include <stdio.h> # include <algorithm> # include <string.h> using namespace std ...
- $Poj2054\ Color\ a\ Tree\ $ 贪心
$poj$ $Description$ 一颗树有 $n$ 个节点,这些节点被标号为:$1,2,3…n,$每个节点 $i$ 都有一个权值 $A[i]$. 现在要把这棵树的节点全部染色,染色的规则是: 根 ...
- 【POJ 2054】 Color a Tree
[题目链接] http://poj.org/problem?id=2054 [算法] 贪心 [代码] #include <algorithm> #include <bitset> ...
- poj2054 Color a Tree
神题.这题是巨毒瘤... 自己写真可谓是: 排空驭气奔如电,上天入地求之遍 上穷碧落下黄泉,两处茫茫皆不见 由于我们知道:不是树形时,不停选值最大的节点可以得到最小代价. 那么我们就能想出一个错误的贪 ...
- Color a Tree & 排列
Color a Tree 题目链接 好不可做?可以尝试一下DP贪心网络流.DP 似乎没法做,网络流也不太行,所以试一下贪心. 考虑全局中最大权值的那个点,如果它没父亲,那么一定会先选它:否则,选完它父 ...
- Color a Tree[HDU1055]
Color a Tree Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tota ...
随机推荐
- 前端开发学习笔记 - 1. Node.JS安装笔记
Node.JS安装笔记 Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. Node.js uses an ...
- linux中shell变量$#,$@,$0,$1,$2的含义解释<转>
linux中shell变量$#,$@,$,$,$2的含义解释: 变量说明: $$ Shell本身的PID(ProcessID) $! Shell最后运行的后台Process的PID $? 最后运行的命 ...
- MySQL主主模式
mysql主主复制配置: HOSTNAME IPADDR PORT节点1:my-prod01.oracle.com 192.168.10.97 3306 节点2:my-prod02.oracle.co ...
- 剑指 Offer——数组中的逆序对
1. 题目 2. 解答 借助于归并排序的分治思想,在每次合并的时候统计逆序对.因为要合并的两个数组都是有序的,如果左半部分数组当前值大于右半部分数组当前值,那么左半部分数组当前值右边的数就都大于右半部 ...
- PHP 常用函数-url函数
urlencode 和 rawurlencode urlencode 和 rawurlencode 两个函数都用来编码 URL 字符串.除了 -_. 之外的所有非字母数字字符都将被替换成百分号(%)后 ...
- 医院里的CR、DR、CT、磁共振、B超都是什么?
转自 百度知道MR CT CR DR DSA X线 都事医学影像疾病诊断的一种. MRI 是磁共振影像检查,可以获得横断面,矢状面和冠状面的影像.空间分辩率好. CT 是一种X线诊断设备,是一种复杂的 ...
- 《深入浅出WPF》学习总结之XAML标签语言一
一.XMAL概览 1.XAML在桌面开发及富媒体网络程序的开发中扮演了HTML+CSS+JS的角色. 2.XAML可以将UI和逻辑代码分离,降低耦合度. 3.XAML是一种单纯的申明形语言 4.XAM ...
- python列表-使用
一.列表用于循环 1.for循环 2. in 和 not in 3.多重赋值
- SUST_ACM_2019届暑期ACM集训热身赛题解
问题A:Hello SUST! 知识点:基本输入输出 C/C++: #include <stdio.h> int main() { int n; scanf("%d", ...
- VBA中Let与Set的区别
Let与Set的区别 1.在“类模块”中 Property Let 语句 在Class块中,是给普通变量进行赋值操作的Property,该种Property将不能在其前面使用Set,因而将不能用户对对 ...