霍夫曼树之切割木板最小总代价问题

                                                        

对于本题的切割方案,在给出了最终的切割结果后,我们其实可以使用倒推的方法,将最终的小木板不断合成大木板,大木板的长度就是本次合并的开销,和相同条件下的切割的开销是一样的。

这样想的话,想要总开销小的话,其实想想的话,就可以知道,肯定是不断先合并最小的.因为比如一个小木块a合并成大木块b之后大木块b又和别的木块合并成大木块c,那么大木块中的开销其实包含了原先小木块a的两倍长度,并且大木块c继续合并的话,之后合并的木块会包含越来越大倍数的小木板a的长度.

根据这种想法,我们就不断取小木板中最小的两块进行合并,并将合并的大木板放入到其他剩余的小木板中继续取最小的两块进行合并.

源代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
#define Max_N 20000
int a[Max_N];
int n;
int solve1()
{
	int count=n;
	int ans=0;
	while(count>1)
	{
		//cout<<count<<endl;
	   sort(a+n-count,a+n);    //对当前剩余的木板进行升序排序
	   int min1=a[n-count];
	   int min2=a[n-count+1];
	   
	   int sum=min1+min2;
	   
	   /* 测试使用 
	   for(int i=0;i<n;i++)
	   {
	   	cout<<a[i]<<" ";
	   }
	   cout<<"--------";
	   cout<<min1<<" "<<min2<<" "<<sum<<endl;*/
	   ans+=sum;
	   a[n-count+1]=sum;
	   count--;
	}
	return ans;
}
int solve2()
{
	int ans=0;
	while(n>1)
	{
	   int min1=0,min2=1;
	   if(a[min1]>a[min2]) swap(min1,min2);
	   
	   for(int i=2;i<n;i++)
	   {
	   	if(a[i]<a[min1])
	   	{
	   		min2=min1;
	   		min1=i;
	   	}
	   	else if(a[i]<a[min2])
	   	{
	   		min2=i;
	   	}
	   }
	   
	   int sum=a[min1]+a[min2];
	   ans+=sum;
	   
	   if(min1==n-1) swap(min1,min2);
	   a[min1]=sum;
	   a[min2]=a[n-1];
	   n--;
	}
	return ans;
}
int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	cout<<solve2()<<endl;
	return 0;
}
solve1函数是我在书上给出的solve2方法的基础上优化的,优化的方面除了代码更加简洁外,此外其复杂度只有O(nlogn),而原先的solve2方法复杂度则有O(n^2).

其实接触过霍夫曼树的同学到这里就可以感觉到本题其实就是个类似于霍夫曼编码的问题。在霍夫曼树中,叶子节点对应的其实就是最终分割的小木板,除了叶子节点之外的节点就是又小木板合并成的大木板。每个大木板的开销其实就是其左右子节点对应的数值之和,进一步变换就是"每个叶子节点与其所处树中深度乘积之和".这里对于霍夫曼树的代价问题就不过多阐述。


PS:现在每天看书上的题目,接触到的题目越来越多,也没太多的时间将每道题写成博客。所以我会每天写两篇博客介绍下当天遇到的个人感觉比较有价值的题目~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值