HDU_1055 && POJ_2054 Color a Tree(贪心)

  这道题整了一下午,最后还是看别人的解题报告弄出来的,先说说我的理解吧。大体处理思路是利用贪心思想,每次取权值最大的节点,不断的将权值最大节点与它的父节点合并。

过程:

1、初始时将序列中的time[i]都置为1,w[i]置为c[i];

2、查找最大的w[i], 返回其位置;

3、将该位置的c[]与它的父节点c[]合并(合并过程就是C_i / T_i,C_i = c[该节点] + c[父节点]T_i = time[该节点]+time[父节点])得到新的父节点w[](w[父节点] = C_i / T_i),如果有节点与pos相连,让它指向pos的父节点;

4、重复2、3,知道合并完;

至于如何求出结果:初始时使ans = sum(c[i]);每次查找到一个最大权值,ans += c[i] * time[父节点]

具体代码如下:

#include <iostream>
#include
<cstdio>

using namespace std;

const int N = 1007;

struct node
{
int t; //time[]
int p; //记录父节点
int c; //c[]
double w; //w[]
}num[N];

int n, r;

int find() //查找最大的权值,返回其位置
{
int pos;
double max = 0;
for(int i = 1; i <= n; i++)
if(num[i].w > max && i != r) //pos不能为根节点
{
max
= num[i].w;
pos
= i;
}
return pos;
}

int main()
{
//freopen("data.in", "r", stdin);
int i, j, a, b, pos, ans, f;
while(scanf("%d%d", &n, &r), n||r)
{
ans
= 0;
for(i = 1; i <= n; i++)
{
scanf(
"%d", &num[i].c);
num[i].w
= num[i].c; //初始时w[i]置为c[i];
num[i].t = 1; //time[i] 置为1;
ans += num[i].c; //初始ans = sum(c[i]);
}
for(i = 1; i < n; i++)
{
scanf(
"%d%d", &a, &b);
num[b].p
= a; //记录父节点,建立树关系
}
i
= n;
while(i > 1)
{
pos
= find(); //找到最大权值的位置
num[pos].w = 0; //找到后将之置0,否则影响下次查找。
f = num[pos].p; //f为父节点
ans += num[pos].c * num[f].t; //将找到的c[pos]*time[f]加入ans
for(j = 1; j <= n; j++)
if(num[j].p == pos)
num[j].p
= f; //如果有节点与pos相连,让它指向pos的父节点
num[f].c += num[pos].c; //C_i = c[该节点] + c[父节点]
num[f].t += num[pos].t; //T_i = time[该节点]+time[父节点]
num[f].w = (double)num[f].c/num[f].t; //合并后的f节点的权值
i--;
}
printf(
"%d\n", ans);
}
return 0;
}
posted @ 2011-08-19 18:31  AC_Von  阅读(1603)  评论(0编辑  收藏  举报