POJ 3253 Fence Repair (哈夫曼树,堆)

30 篇文章 0 订阅
本文通过一道算法题——POJ 3253 Fence Repair,阐述了如何应用哈夫曼树进行求解。题目要求以最低费用砍木板,通过分析哈夫曼树的特性,证明了按长度从大到小砍木板能实现最低费用。哈夫曼树的最小堆模拟可以高效地找到每次应砍的最长木板。代码实现中使用了手动实现的优先队列,并确保结果使用long long类型以避免溢出。
摘要由CSDN通过智能技术生成

一道很明显的哈夫曼树题

看discuz有人不知道为什么是哈夫曼树,这里稍微证明一下

题目说砍木板,收费等于要砍的木板的长度,要求费用最少

其实这里有点跟贪心的策略相同,总是要砍这些长度的,所以先把“长的”(不一定是单条长的,可以是合起来长的)先砍掉,这样很明显优于把“长的”留在后面砍的情况(因为那个长度至少要被收费两次)

现在回想一下哈夫曼树的结构,不知道哈夫曼树的请看:http://baike.baidu.com/view/127820.htm

哈夫曼树主要用于编码,用哈夫曼编码可以减少传输的数据量,特点是编码的长度不同

哈夫曼的结构是每次把最小的两个出队合并,再压入队列,重复。

如果把哈夫曼树的建树过程反过来看,正好是我们要求的每次把最长的砍掉的情况。

可以发现哈夫曼的结构保证小的总在下面,大的在上面,正好符合题目要求。可以证明要求的费用正好等于哈夫曼树的中间节点的和(除去叶子节点)。

不会证明的画个哈夫曼树,然后比较一下哈夫曼树跟最小费用砍法就能明白了。

实际上不用真正建树,只要把中间节点值加起来就行了。

建树是用堆模拟的优先队列可以提高效率,毕竟每次查询最小值是o(lgN)

下面给出代码,手写的优先队列,结果要用long long。


#include <stdio.h>
int piece[20010];

void heap(int n,int N)
{
	int i=0,x=n;
	if(2*n+1<N && piece[2*n+1]<piece[x])
	{
		x=2*x+1;
	}
	if(2*n+2<N && piece[2*n+2]<piece[x])
	{
		x=2*n+2;
	}
	if(x!=n)
	{
		piece[x]=piece[x]^piece[n];
		piece[n]=piece[x]^piece[n];
		piece[x]=piece[x]^piece[n];
		heap(x,N);
	}
	return;
}

void buildheap(int N)
{
	int i;
	for(i=N>>1;i>=0;--i)
	{
		heap(i,N);
	}
	return;
}

long long hafuman(int N)
{
	int i=0,length=N;
	long long sum=0,tmp=0;
	buildheap(length);
	for(i=1;i<N;++i)
	{
		tmp=piece[0];
		--length;
		piece[0]=piece[length];
		heap(0,length);
		tmp+=piece[0];
		piece[0]=tmp;
		heap(0,length);
		sum+=tmp;
	}
	return sum;
}

int main()
{
	int N,i=0;
	scanf("%d",&N);
	for(i=0;i<N;++i)
	{
		scanf("%d",piece+i);
	}
	printf("%I64d\n",hafuman(N));
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值