算法导论作业 问题 A: algorithm-锯木棒

题目描述

xiaok大佬最近再雇佣工人给他掰木棒。把一根长为L的木棒锯成两段,他需要支付给工人L元钱。xiaok大佬一开始只有长为L的一根木棒,他想把它锯成n段,每段长度分别为L1,L2,…,Ln,问xiaok大佬最少要付给工人多少钱?
输入
第一行两个整数n,L(1<n<103,n<L<109)
第二行n个整数L1,L2,…,Ln(0<Li<L,且保证L1+L2+…+Ln=L)
输出
输出一个整数,表示最小花费
样例输入
3 21
8 5 8
样例输出
34
思路:首先考虑到的是明显可以使用贪心算法,即:每次折掉n段中最大的那一段,就可以使得下一次折棒的花费尽可能的小。编写的代码如下:

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
	int n, L;
	cin >> n >> L;
	int MinCost = 0;
	int* Ln = new int[n];
	for (int i = 0; i < n; i++)
		cin >> Ln[i];
	sort(Ln, Ln + n);
	for(int i=n-1;i>0;--i)
	{
		MinCost += L;
		L = L - Ln[i];
	}
	cout << MinCost;
}

然而提交到OJ后只有25%的AC,也就是说想法应该是基本错了。问题出在哪儿呢?老师指出这题应该是哈夫曼树,我对比了一下自己的贪心和哈夫曼树的区别,发现我所想的贪心存在缺陷,每次是一定要选出最终结果中的一段中的最大值的,其实折出这个n段中的最大值并不能使下一次的折棒耗费最小,比如
4 29
4 8 9 8
如果第一次折出20 9,那么下一次的耗费将是20,折出12 8;再下一次耗费12,折出8 4;我们可以看到耗费分别是29 20 12;
如果使用哈夫曼树的构建方式,则是29 17 12。
区别就在于,折棒会产生两段,两端都是可以再折的,而我所设想的贪心算法直接放弃了其中一段的折。最大的一段不一定非得要最先折掉,下一步的耗费才最小。哈夫曼算法自底向上,能够确保遍历出综合考虑每次最小的折棒代价。
以下是正确ac的代码:

#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
int main()
{
	int n, L;
	cin >> n >> L;
	int MinCost = 0;
	int* Ln = new int[n];
	priority_queue<int, vector<int>, greater<int>> pq;
	for (int i = 0; i < n; i++)
	{
		cin >> Ln[i];
		pq.push(Ln[i]);
	}
	while (pq.size() > 1)
	{
		int temp1 = pq.top();
		pq.pop();
		int temp2 = pq.top();
		pq.pop();
		int tempsum = temp1 + temp2;
		pq.push(tempsum);
		MinCost += tempsum;
	}
	cout << MinCost;
	delete []Ln;
}

(个人反思:其实我之前太贪玩,直到这次作业都没有真正学在编程中使用数据结构的知识,比如这次所使用的优先队列,还有容器的概念。这次是第一次使用,要开始抓紧学习了。)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值