POJ 2054 Color a Tree#贪心(难,好题)
代码借鉴此博:http://www.cnblogs.com/vongang/archive/2011/08/19/2146070.html
其中关于max{c[fa]/t[fa]}贪心原则,此博有很好的解释:http://www.cnblogs.com/rainydays/p/3271277.html
在此引用其中几段话:
试想,如果没有父节点排在节点之前的限制,那么这个题目非常简单,只需要将结点按照权值从大到小排列即可。加上了这个限制之后,如果权值最大的那个节点一旦满足了条件(父节点被排在了之前的某个位置),那么这个权值最大的节点一定要紧挨着这个父节点,即把这个权值最大的节点排在它所能排的最前面的位置。因为对于这个节点如果不受限制应该排在第一位,而有了限制,在满足了限制之后也应把它尽可能地排在前面。所以它一定是挨着父节点的。那么现在在最终的排列中我们确定了两个节点的前后相邻关系,将他们绑定在了一起。
试想如果保持这个相邻关系的同时去掉其他节点的限制,那么我们应该如何排列呢?我们假设绑定在一起的两节点是a和b。现有一个另外的节点x,我们看两种排列xab,abx对最终的计算结果有什么影响。x*i+a*(i+1)+b*(i+2); a*i + b*(i+1) + x*(i+2)。后者减去前者等于2x-(a+b)。即将x从ab之前挪到ab之后,ab各左移1位,结果减小a+b。x右移2位结果增加2x。因此两者谁在前谁在后我们只需要比较a+b和2x即可,也可以比较(a+b)/2和x。
将这个定理进行一下推广,绑定在一起的不一定是两个节点,可以是一个更长的序列,与这个序列进行比较看谁放在前面的也可以是一个序列。设一个序列有n1个节点,第二个序列有n2个节点。那么我们比较两者谁放在前面的时候需要比较的是(n1个权值之和×n2)和(n2个权值之和×n1)。即左移和右移产生的结果变化。当然也可以比较(n1个权值之和/n1)和(n2个权值之和/n2)。
我们可以再次进行推广,如果我们要排列的不是节点,而是许多序列的话,那么我们只需要计算每个序列权值的平均数(例如:n个节点的序列,要计算n个权值之和/n),然后按照这个平均数从大到小排列即可使得计算结果最小。这样就可以让序列与节点有了一个统一的衡量值——平均数。
这样一来,我们就可以将上面的绑定两节点的操作看成是将问题规模缩小的操作,在帮定两节点的同时我们在树中也将两节点合并,变为一个节点,即将子节点的孩子变为父节点的孩子。然后合并后的节点的权值是合并在这个节点中的所有节点的权值的平均数。我们成功的将问题规模减小了1。只需要不断这样做即可将问题缩减为只有一个节点。
以下为AC code:
//贪心:如果这棵树中有最大权值点X(非根),
//那么一旦X的父节点Y已经染色,就应该立刻染X
//于是X和Y合并成一个点集,
//新点集的权值=(新点集中所有点的权值和)/(新点集中点的个数)
//类似的,该点集可以看为一个点
//重复上述贪心思路,直到最后只剩下一个根r点集
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std; const int N=1005; struct Node
{
int f;//父结点
int t;//时间
int c;//原权值
double w;//贪心权值(c/t)
}node[N]; int n,r; int findPos()
{
int pos;
double wmax=0;
for(int i=1;i<=n;i++)
if(node[i].w>wmax&&i!=r)
{
wmax=node[i].w;
pos=i;
}
return pos;
} int main()
{
while(scanf("%d%d",&n,&r)&&n+r)
{
int pos,fa,res=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&node[i].c);
node[i].w=node[i].c;//将贪心权值w初始化为原权值c
node[i].t=1;//时间初始化为1
res+=node[i].c;//结果初始化为sum of所有原权值c
}
int u,v;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
node[v].f=u;//记录父结点
} for(int i=1;i<n;i++)
{
pos=findPos();//找到贪心权值最大的位置
node[pos].w=0;//置0,以便下次查找时跳过之
fa=node[pos].f;//fa为pos的父结点
res+=node[pos].c*node[fa].t;//res+=pos原权值*fa父结点时间(node[fa].t实际上代表,点集中有几个点)
for(int j=1;j<=n;j++)
if(node[j].f==pos)
node[j].f=fa;//若有j的父结点是pos,则将j的父结点改为fa,建立新集合
node[fa].t+=node[pos].t;//更新以fa为父结点的点集内点的个数(即加上以pos为父结点的点集内点的个数)
node[fa].c+=node[pos].c;//更新点集的话,那权值自然也要更新
node[fa].w=(double)node[fa].c/node[fa].t;//贪心原则:新点集权值和/新点集中点的个数
}
printf("%d\n",res);
}
return 0;
}
POJ 2054 Color a Tree#贪心(难,好题)的更多相关文章
- POJ 2054 Color a Tree (贪心)
$ POJ~2054~Color~a~Tree $ $ solution: $ 我们先从题中抽取信息,因为每个点的费用和染色的次数有关,所以我们可以很自然的想到先给权值大的节点染色.但是题目还说每个节 ...
- 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
贪心.... Color a Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: ...
- 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 ...
随机推荐
- Kindeditor JS 富文本编辑器图片上传指定路径
js //================== KindEditor.ready(function (K) { var hotelid = $("#hotelid").val(); ...
- 关于web多标签多条件筛选的思考以及缓存的正确使用方法(上)
做项目的过程中,发现一次远程链接数据库的耗时大概是300ms~400ms,切身体会到了前辈们经常说的减少链接的重要性,用了缓存后页面的打开时间从1.5s减少到400ms 前提: 那么来说一说正题,we ...
- linux 学习-用户&群组&权限
Linux用户&群组&权限 ⦁ Linux安全性模型 1)Linux使用User和Group控制使用者对文件的存取权限 2)用户使用账号和口令登录Linux 3) ...
- Oracle笔记(1) 简单查询、限定查询、数据的排序
Oracle笔记(四) 简单查询.限定查询.数据的排序 一.简单查询 SQL(Structured Query Language) 结构化查询语言,是一种数据库查询和程序设计语言,用于存取数据以及 ...
- 5754Life Winner Bo
给定一个n*m的矩阵,有四种棋子(国际象棋的王,王后,骑士,车).起点在(1,1)先走到(n,m)获胜. 分析:车是nim博弈.王后是威佐夫博弈.王和骑士写两个1000*1000的预处理即可. hdu ...
- CentOS 7.2 部署Saltstack
CentOS 7.2部署Saltstack 一.环境介绍: 服务器名称 IP地址 Salt-Master 192.168.30.141 Slave1 192.168.30.131 Slave2 192 ...
- js两种生成对象模式(公有成员和成员私有)
假设有个需求,创建一个book类,有isbn码,书名,作者 :可以对isbn进行数据完整性校验:--js设计模式 <script type="text/javascript" ...
- 【IE6的疯狂之九】li在IE中底部空行的BUG
曾经写过[IE6的疯狂之六]li在IE中底部3像素的BUG(增加浮动解决问题),原文地址:http://www.css88.com/archives/421: IE6 BUG大全: http://ww ...
- [河南省ACM省赛-第三届] 网络的可靠性 (nyoj 170)
题目链接:http://acm.nyist.net/JudgeOnline/problem.php?pid=170 根据题意,需要找到度数为1的结点个数,如下图: #include<iostre ...
- Zeppelin0.5.6使用hive解释器
此zeppelin为官方0.5.6版,可能还在孵化阶段,可能出现一些bug吧. 配置 cp zeppelin-env.sh.template zeppelin-env.sh vi zeppelin-e ...