码迷,mamicode.com
首页 > 其他好文 > 详细

HDU ACM 1055 Color a Tree->树上的贪心

时间:2015-06-07 09:40:49      阅读:256      评论:0      收藏:0      [点我收藏+]

标签:c   c++   acm   算法   编程   

题意:给一棵树染色,这棵树有n个节点,根结点是r。每个结点都有一个权值ci,开始时间为0,每染色一个结点需要耗时1,每个结点染色代价为ci*ti(ti为当前时间),每个结点只有在父结点被染色的条件下才能被染色。求染完整棵树要花费的最小代价。

分析:贪心总体思路,每次找一个权值最大的节点,如果是根节点,则首先对它染色,否则的话可以得出一个结论,在它父亲已经染色的情况下,立刻给它染色是最优的。对于第二种情况,当它不是根节点,且已对它父亲染了色,则一定会立刻对它染色,所以可以把它和它父亲合并为同一个节点,它和它父亲的儿子都成为了新节点的儿子,它的父亲的父亲则是新节点的父亲。为了能继续贪心,给每个节点赋上两个权值,ti表示对第i个节点图色所需时间(第i个节点实际包含的节点数),si表示第i个节点的总权值(第i个节点实际包含的节点的权值和)。此时,定义一个节点的权值等于si比上ti。可以证明在新的权值定义下,以上贪心同样成立。

结论:对于一个非根结点,它具有非根结点的最大权值,那么访问完它的父节点后立即访问它能使得代价最小。

使用并查集。

过程;

1、初始将序列中的time[i]都置为1,w[i]置为c[i];
2、查找最大的w[i],得到位置;
3、将该位置的s与它的父节点s合并(就是C_i / T_i,C_i = c[该节点] + c[父节点],T_i = time[该节点]+time[父节点])得新的父节点w[](w[父节点] = C_i / T_i),如果有节点与pos相连,让它指向pos的父节点。
4、重复2、3,直到合并完(或者所有点都被访问);

最终会得到一个访问序列,该序列能得到最小的染色权值。

#include<iostream>
using namespace std;

#define N 1010
double b[N];      //合并节点权值和
int Next[N];      //记录最优访问的下一个节点
int f[N];         //记录父节点
int cnt[N];       //合并节点的节点数
int fa[N];        //并查集使用
bool vis[N];
int a[N];      //权值

int child(int r)  //找到最优访问序列的最后一个节点(子节点)
{
	if(Next[r]==r) return r;
	return child(Next[r]);
}

int father(int x)  //找到祖先节点,带路径压缩
{
	if(fa[x]==x) return x;
	fa[x]=father(fa[x]);
	return fa[x];
}

int sovle(int n,int r)
{
	double max;
	int j,i,u,v,ans,k;

	memset(vis,false,sizeof(vis));
	vis[r]=true;
	for(j=1;j<n;j++)  //处理n-1次
	{
		max=0;
		for(i=1;i<=n;i++)
			if(!vis[i] && max<b[i]/cnt[i])
			{
				max=b[i]/cnt[i];
				v=i;
			}
		u=child(f[v]);
		Next[u]=v;
		fa[v]=u;
		u=father(v);  //这句并不多余,可以进行路径压缩
		cnt[u]+=cnt[v];
		b[u]+=b[v];
		vis[v]=true;
	}
	ans=0;
	k=1;
	while(r!=Next[r])  //处理最优序列
	{
		ans+=k*a[r];
		k++;
		r=Next[r];
	}
	ans+=k*a[r];
	return ans;
}

int main()
{
	int n,i,u,v,r;

	while(scanf("%d%d",&n,&r)==2 && n+r)
	{
		for(i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			b[i]=a[i]*1.0;
			fa[i]=f[i]=Next[i]=i;
			cnt[i]=1;
		}
		for(i=1;i<n;i++)
		{
			scanf("%d%d",&u,&v);
			f[v]=u;
		}
		printf("%d\n",sovle(n,r));
	}
    return 0;
}


HDU ACM 1055 Color a Tree->树上的贪心

标签:c   c++   acm   算法   编程   

原文地址:http://blog.csdn.net/a809146548/article/details/46391581

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!