算法:
算法证明:http://hi.baidu.com/cheezer94/item/7b4a15214b2050022b0f1c0a
代码来源:http://www.cppblog.com/notonlysuccess/archive/2009/07/02/88793.html
ò 1.标记根节点为第一个访问的节点。
ò 2.求出当前未访问节点中的最大点权节点i。
ò 3.将i和它的父亲j合并为一个节点,节点权值为两者权值的算术平均数。在序列P中将j的后继置为i。同时更新树的信息。
ò 4.若当前树中节点数大于1,则转第2步。
ò 5.树的大小为1时算法结束。
ò 6.扫描求得的P序列得到答案。
ò 时间复杂度:O(N^2)。期望得分50-70分。
#include "stdio.h"
#include "string"
#define maxn 1001
struct H{
int val;
int cost;
int time;
void clear() {
val = cost = time = 0;
}
}hh[maxn];
int father[maxn];
int main() {
int n,r,i;
while(scanf("%d%d",&n,&r),n+r) {
for(i =1 ; i <= n ; i ++) {
scanf("%d",&hh[i].cost);
hh[i].val = hh[i].cost;
hh[i].time = 1;
}
for(i = 1; i < n ; i ++) {
int a,b;
scanf("%d%d",&a,&b);
father[b] = a;
}
while(true) {
int idx = 0;
for(i = 1 ; i <= n ; i ++) {
if(i != r && hh[i].time && (idx == 0 || hh[idx].val * hh[i].time < hh[i].val * hh[idx].time)) {
idx = i;
}
}
if(idx == 0) break;
int f = father[idx];
hh[f].cost += hh[idx].cost + hh[idx].val * hh[f].time;
hh[f].val += hh[idx].val;
hh[f].time += hh[idx].time;
hh[idx].clear();
}
printf("%d\n",hh[r].cost);
}
return 0;
}
(使用映射二叉堆)
ò 注意到我们每次操作需要得到当前最大权对应的节点i并将i的儿子的父亲改为i的父亲。
ò O(N)的扫描成为算法复杂度的瓶颈。
ò 如何高效求最大值?
ò 推荐数据结构:最大堆(O(LogN))。
ò 如何高效地将i的儿子的父亲改为i的父亲?
ò 推荐数据结构:并查集(O(α(N)))。
ò 总的时间复杂度:O(NLogN)。期望得分100分。
注意根不能放到堆中!
#include "stdio.h"
#include "string"
#define maxn 1001
//-----------------------Binary Heap------------------------------------
struct Heap {
int val,cost,time,idx;
}hh[maxn];
int pos[maxn];
int len;
bool Prior(Heap a,Heap b) {
return a.val * b.time > b.val * a.time;
}
void Push(Heap s) {
int i;
for(i = ++len ; i > 1 && Prior(s,hh[i/2]); i /= 2) {
hh[i] = hh[i/2];
pos[hh[i].idx] = i;
}
hh[i] = s;
pos[hh[i].idx] = i;
}
Heap Pop(int idx) {
if(idx == -1) return hh[0];
Heap ret = hh[idx];
Heap last = hh[len--];
int i,s;
for(i = idx ; i * 2 <= len; i = s) {
s = i * 2;
if(s + 1 <= len && Prior(hh[s+1],hh[s])) {
s ++;
}
if(Prior(hh[s],last)) {
hh[i] = hh[s];
pos[hh[i].idx] = i;
} else {
break;
}
}
hh[i] = last;
pos[hh[i].idx] = i;
for(i = idx ; i > 1 && Prior(hh[i],hh[i/2]); i /= 2) {
Heap buf = hh[i];
hh[i] = hh[i/2];
hh[i/2] = buf;
pos[hh[i].idx] = i;
pos[hh[i/2].idx] = i/2;
}
return ret;
}
//---------------------------------------------------------------
int father[maxn];
int main() {
int n,r,i;
hh[0].cost = hh[0].time = hh[0].val = 0;
while(scanf("%d%d",&n,&r),n+r) {
len = 0;
Heap root;
for(i =1 ; i <= n ; i ++) {
Heap buf;
scanf("%d",&buf.cost);
buf.val = buf.cost;
buf.time = 1;
buf.idx = i;
if(i == r) {
root = buf;
} else {
Push(buf);
}
}
for(i = 1 ; i < n ; i ++) {
int a,b;
scanf("%d%d",&a,&b);
father[b] = a;
}
while(len) {
Heap max = Pop(1);
int f = father[max.idx];
if(f == r) {
root.cost += max.cost + max.val * root.time;
root.time += max.time;
root.val += max.val;
} else {
Heap fa = Pop(pos[f]);
fa.cost += max.cost + max.val * fa.time;
fa.time += max.time;
fa.val += max.val;
fa.idx = f;
Push(fa);
}
pos[max.idx] = -1;
}
printf("%d\n",root.cost);
}
return 0;
}