UVALive6533 inverting huffman

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=47668

题解:

//思路就是先把二叉树补全,从最下层开始给叶子节点赋值,每一层的叶子节点能取到的最小值为下一层中的最大值
#include<stdio.h>
#include<algorithm>
using namespace std;
int n,top;
typedef struct Huffman
{
	int dis;
	long long l;
	bool flag;
}H;
H HT[200];
bool cmp(const H &a,const H &b)
{
	return a.dis>b.dis;
}
bool cmp2(const H &a,const H &b)
{
    return a.l<b.l;
}
long long getAns()
{
	top=n;
	int s=0,index;
	/**************************
	以下代码是为了补全非叶子节点使其构成完整的二叉树
	****************************/
	while(top-s>1)
	{
		int cnt=0;
		for(int i=s;i<top;i++)
		{
			if(!cnt)
				cnt++;
			else if(HT[i].dis==HT[i-1].dis)
				cnt++;
			else
				break;
		}
		s+=cnt;
		index=s;
		while(cnt>0)
		{
			for(int i=top;i>index;i--)
				HT[i]=HT[i-1];
			HT[index].dis=HT[s-1].dis-1;
			HT[index].flag=false;
			index++;
			top++;
			cnt-=2;
		}
	}
	/***************************************/
	s=0;
	while(top-s>1)
	{
		int c=0;
		for(int i=s;i<top;i++)
		{
			if(HT[i].dis==HT[0].dis)
			{
				c++;
				HT[i].l=1;
				continue;
			}
			if(c==0)
				c++;
			else if(HT[i].dis==HT[i-1].dis)
				c++;
			else
				break;
		}
		sort(HT+s,HT+s+c,cmp2);//因为最优二叉树中每个非叶子节点都是下一层中值最小的两个结点之和,所以应该先把下层的结点排个序
		int cc=0;
		for(int i=s+c;i<top;i++)
		{
			if(cc==0)
				cc++;
			else if(HT[i].dis==HT[i-1].dis)
				cc++;
			else
				break;
		}
		int temp=0,t=0;
		long long Max=-1;//Max用来记录每层的最大值
		for(int i=s+c;i<s+c+cc;i++)
		{
			if(!HT[i].flag)
			{
				HT[i].l=HT[s+temp].l+HT[s+temp+1].l;
				if(Max<HT[s+temp].l)
					Max=HT[s+temp].l;
				if(Max<HT[s+temp+1].l)
					Max=HT[s+temp+1].l;
				temp+=2;
			}
		}
		for(int i=s+c;i<s+c+cc;i++)
		{
			if(HT[i].flag)
				HT[i].l=Max;//叶子节点均赋值为下一层的最大值
		}
		s=s+c;
	}
	long long ans=0;
	for(int i=0;i<top;i++)
		if(HT[i].flag)
			ans+=HT[i].l;
	return ans;
}
int main()
{
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=0;i<n;i++)
		{
			scanf("%d",&HT[i].dis);
			HT[i].flag=true;
		}
		sort(HT,HT+n,cmp);
		printf("%lld\n",getAns());
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值