您的位置:首页 > Web前端

POJ 3253 Fence Repair 经典问题

2014-03-13 09:39 477 查看
【题意简述】:将一块长木板切割成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追加到编码的末尾,到达每个叶子节点时就能得到该节点对应的码字了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: