POJ 2054 Color a Tree 贪心

转载请注明出处,谢谢 http://blog.csdn.net/ACM_cxlove?viewmode=contents           by---cxlove


犀利的贪心,开始完全没有正确贪心的思路。

还是看了网上的题解。

根据这种题目,肯定我们首先考虑最大的c,可是由于有父节点的限制,但是对于某个最大的c,它必定是紧随父节点之后,这样便可以把这两个节点合并成一个节点,c表示集合的权值,num表示节点的个数,我们利用c/num进行权衡。

pre表示父节点

next,start采用前向星存储

 

#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<queue>
#include<string>
#include<vector>
#define eps 1e-6
#define LL long long
#define LD long double
#define pi acos(-1.0)
#define inf 1<<30
using namespace std;
struct Node{
	int idx,next;
}a[1005];
int cnt,n,root,c[1005],num[1005],pre[1005],start[1005];
bool visit[1005];
int addedge(int u,int v){
	a[cnt].idx=v;
	a[cnt].next=start[u];
	return cnt++;
}
int find_root(){
	double mmax=0;
	int k;
	for(int i=1;i<=n;i++)
		if(!visit[i]&&(double)c[i]/num[i]>mmax&&i!=root){
			mmax=(double)c[i]/num[i];
			k=i;
		}
	return k;
}
void Union(int k,int p){
	num[p]+=num[k];
	c[p]+=c[k];
	for(int i=start[k];i;i=a[i].next)
		pre[a[i].idx]=p;
}
int slove(){
	int ans=0;
	for(int i=1;i<n;i++){
		int k=find_root();
		visit[k]=true;
		int p=pre[k];
		while(visit[p]) p=pre[p];
		ans+=num[p]*c[k];
		Union(k,p);
	}
	return ans+c[root];
}
int main(){
	while(scanf("%d%d",&n,&root)!=EOF&&n+root){
		memset(start,0,sizeof(start));
		memset(visit,false,sizeof(visit));
		for(int i=1;i<=n;i++){
			scanf("%d",&c[i]);
			num[i]=1;
		}
		cnt=1;
		for(int i=1;i<n;i++){
			int u,v;
			scanf("%d%d",&u,&v);
			start[u]=addedge(u,v);
			pre[v]=u;
		}
		printf("%d\n",slove());
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值