1. 程式人生 > >UPC1430 Color a Tree(貪心)

UPC1430 Color a Tree(貪心)

題意:

    一棵樹,n個節點,n-1條邊,每個節點有權值val。Time為當前時間,初始為0,每染一次需要 1s ,對節點 i 染色時要花費 val*Time ,且要對 i 染色要保證 i 的父親節點已被染色。問染完所有節點的最小花費。

思路:

    每次找到一個權值最大的節點,如果它是根節點,則首先對它染色。否則,在對它的父親已經染色的情況下,立刻給它染色一定是最優的,所以可以把它和它父親合併為同一個節點,它和它父親的兒子都成為了新節點的兒子,它的父親的父親則是新節點的父親。為了能繼續貪下去,我們給每個節點賦上兩個權值,num_node表示對第i個節點塗色所需的時間(第i個節點實際包含的節點數),sumc表示第i個節點的總權值(第i個節點實際包含的節點的權值和)。此時,我們定義一個節點的權值就等於sumc/num_node。

程式碼:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5;

int n, root, ans, fa[maxn], Time[maxn], val[maxn];
void solve(){
	for(int i=1; i<n; i++){
		double maxnum=0;
		int maxi;
                //此處找最大值時可用優先佇列優化
		for(int j=1; j<=n; j++){
			if(val[j]*1.0/Time[j]>maxnum && j!=root)
				maxnum=1.0*val[j]/Time[j], maxi=j;
		}
		for(int j=1; j<=n; j++)
			if(fa[j]==maxi)
				fa[j]=fa[maxi];
		ans += Time[fa[maxi]]*val[maxi];
		Time[fa[maxi]] += Time[maxi];
		val[fa[maxi]] += val[maxi];
		val[maxi] = 0;
	}
	cout << ans << endl;
}
int main()
{
	while(cin >> n >> root && (n+root)){
		for(int i=1; i<=n; i++){
			cin >> val[i];
			ans+=val[i], Time[i]=1;
		}
		int a, b;
		for(int i=1; i<n; i++)
			cin >> a >> b, fa[b]=a;
		solve();
	}
}