POJ2054Color a Tree(贪心)

Color a Tree
Time Limit: 1000MS Memory Limit: 30000K
Total Submissions: 8297 Accepted: 2861
Description

Bob is very interested in the data structure of a tree. A tree is a directed graph in which a special node is singled out, called the “root” of the tree, and there is a unique path from the root to each of the other nodes.

Bob intends to color all the nodes of a tree with a pen. A tree has N nodes, these nodes are numbered 1, 2, …, N. Suppose coloring a node takes 1 unit of time, and after finishing coloring one node, he is allowed to color another. Additionally, he is allowed to color a node only when its father node has been colored. Obviously, Bob is only allowed to color the root in the first try.

Each node has a “coloring cost factor”, Ci. The coloring cost of each node depends both on Ci and the time at which Bob finishes the coloring of this node. At the beginning, the time is set to 0. If the finishing time of coloring node i is Fi, then the coloring cost of node i is Ci * Fi.

For example, a tree with five nodes is shown in Figure-1. The coloring cost factors of each node are 1, 2, 1, 2 and 4. Bob can color the tree in the order 1, 3, 5, 2, 4, with the minimum total coloring cost of 33.

Given a tree and the coloring cost factor of each node, please help Bob to find the minimum possible total coloring cost for coloring all the nodes.
Input

The input consists of several test cases. The first line of each case contains two integers N and R (1 <= N <= 1000, 1 <= R <= N), where N is the number of nodes in the tree and R is the node number of the root node. The second line contains N integers, the i-th of which is Ci (1 <= Ci <= 500), the coloring cost factor of node i. Each of the next N-1 lines contains two space-separated node numbers V1 and V2, which are the endpoints of an edge in the tree, denoting that V1 is the father node of V2. No edge will be listed twice, and all edges will be listed.

A test case of N = 0 and R = 0 indicates the end of input, and should not be processed.
Output

For each test case, output a line containing the minimum total coloring cost required for Bob to color all the nodes.
Sample Input

5 1
1 2 1 2 4
1 2
1 3
2 4
3 5
0 0
Sample Output

33
Source

Beijing 2004

个人感觉这题很神仙
首先我们可以很容易找到一个错误的贪心算法(每一步在可以被染色的点里选权值最大的染色),然而我们很容易构造一棵树,让一个权值很小的节点下面有很多权值很大的节点,另一个权值较大的点却没有子节点。
但是我们可以从中得到一个正确的性质:树中除根节点外最大的点,一定会在它的父节点被染色后立即染色。
我们可以想到这两个操作是连续的,然后我们可以把这两个节点合并,合并得到的权值为这两个点的权值的平均值。
接下来是很神仙的证明

假设有权值为x,y,z的三个点,x和y的操作是连续的,那么有两个可能的方案
1.先染x,y
—————w=x+2y+3z
2.先染z
—————w=z+2x+3y
然后我们比较w的大小,给两边加上(z-y)除以2
1.————w=(x+y)/2+2*z;
2.————w=z+2*((x+y)/2);
这就变成了权值为(x+y)/2和z的两个点的次序!!!!!!

然后我们可以想到一个算法,记录每个点是由多少个点合并来的,这个点的权值就等于原始权值和除以原始点数
然后我们不断的合并,最后一棵树就合并成了一个点,值得注意的是我们要保存顺序,最后按照顺序计算它的总代价


#include  <iostream>
#include   <cstring>
#include    <cstdio>
#include   <cstdlib>
#include     <cmath>
#include    <string>
#include    <vector>
#include      <list>
#include       <map>
#include     <queue>
#include     <stack>
#include    <bitset>
#include <algorithm>
#include  <assert.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
//head
const int maxn = 1100;

int n,r;
struct  node
{
    int t,p,c;
    double w;
} num[maxn];

int find()
{
    double ma = 0;
    int res;
    rep(i,1,n+1)
    {
        if(i != r&&num[i].w > ma)
        {
            ma = num[i].w;
            res = i;
        }
    }
    return res;
}

int main()
{
    while(scanf("%d%d",&n,&r)!=EOF&&(n!=0||r!=0))
    {
        int ans = 0;
        rep(i,1,n+1)
        {
            scanf("%d",&num[i].c);
            num [i].w = num[i].c;
            num[i].t = 1;
            ans += num[i].c;
        }
        rep(i,1,n)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            num[b].p = a;
        }
        rep(i,1,n)
        {
            int pos = find();
            num[pos].w = 0;
            int f = num[pos].p;
            ans += num[pos].c*num[f].t;
            rep(j,1,n+1)
                if(num[j].p == pos)
                {
                    num[j].p = f;
                }
            num[f].c += num[pos].c;
            num[f].t += num[pos].t;
            num[f].w = double(num[f].c)/num[f].t;
        }
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39239844/article/details/81253979