POJ 3253 Fence Repair 经典问题

【题意简述】:将一块长木板切割成N块。准备切成的木板的长度为L1、L2、……LN,未切割前模板的长度恰好为切割后模板的长度总和。求切割的花费。

例如:长度为21的木板要成长度为5、8、8的三块木板。长21的木板切成长为13和8的板时,开销为21。再将长度为13的板切成长度为5和8的板时,开销为13因此合计开销就是34。

限制条件:1  <= N <=20000

  0  <= Li <=50000

【解题思路】:拿到这样一道题,不难了解。切割的方法可以用一颗二叉树来描述!这里每一个叶子的节点就对应了切割出的一块块木板。叶子节点的深度就对应了为了得到对应木板所需的切割次数,开销的合计就是各叶子节点的

木板的长度 *节点的深度

的总和。

所以最佳的切割方法所具有的性质就是这样的:

最短的板 与 此段的板的节点应当是兄弟节点。

对于最优解来说,最短的板应该是深度最大的叶子节点之一。所以与这个叶子节点同一深度的兄弟节点一定存在,并且由于同样是最深的叶子节点,所以应该对应于次短的板。

因此我们便可以将Li 按照大小排序,最短的是L1,次短的是L2。如果在二叉树中就是兄弟节点,就以为这他们是从一块长度为(L1+L2)的木板上切割下来的。

至此我们便可以通过STL中的优先队列来解决此题。详见代码:

// stl 优先队列
// 480K 32Ms
#include<iostream>
#include<vector>
#include<queue>
using namespace std;

//比较规则,最小优先! 
class cmp
{
public:
	bool operator()(const __int64 a,const __int64 b)const
	{
		return a>b;
	}
};

int main(void)
{
	int n; //木板的个数 
	while(cin>>n)
	{
		priority_queue<__int64,vector<__int64>,cmp>Queue;//定义优先队列
		for(int i = 1;i<=n;i++)
		{
			__int64 temp;
			scanf("%I64d",&temp);
			Queue.push(temp);//输入要求的木板长度(费用)并入队。 
		}
		
		__int64 mincost = 0;//最小费用
		while(Queue.size()>1)//当队列中的小于等于一个元素时跳出 
		{
			__int64 a = Queue.top();
			Queue.pop();
			__int64 b = Queue.top();//两次取得队首的元素,即两个最小值! 
			Queue.pop();
			Queue.push(a+b);//入队 
			mincost += a+b;
		} 
		printf("%I64d\n",mincost);
		while(!Queue.empty())//清空队列 
			Queue.pop(); 
	}
	return 0;
}
另外,此题还可应用Huffman 编码的思想俩解决,读者可以先去了解一下Huffman编码的思想,

Huffman Tree 也称为最优二叉树。我们可以将木板对应的换成字符,长度换成频度就可以了,这样在生成的儿茶数中,从根出发,走向左边就将0,走向右边就将1追加到编码的末尾,到达每个叶子节点时就能得到该节点对应的码字了。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值