合并果子

为了防止抄袭代码,本人只供应伪代码

1.题目:

合并果子

成绩 10 开启时间 2013年03月19日 星期二 14:40
折扣 0.8 折扣时间 2013年03月28日 星期四 14:40
允许迟交 关闭时间 2013年06月30日 星期日 14:40

在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。

     例如有3种果子,数目依次为1,2,9。可以先将 1、2堆合并,新堆数目为3,耗费体力为3。接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为 12。所以多多总共耗费体力=3+12=15。可以证明15为最小的体力耗费值。

【输入】包括两行,第一行是一个整数n(1≤n≤10000),表示果子的种类数。第二行包含n个整数,用空格分隔,第i个整数ai(1≤ai≤20000)是第i种果子的数目。

【输出】包括一行,这一行只包含一个整数,也就是最小的体力耗费值。输入数据保证这个值小于231。

  测试输入关于“测试输入”的帮助 期待的输出关于“期待的输出”的帮助 时间限制关于“时间限制”的帮助 内存限制关于“内存限制”的帮助 额外进程关于“{$a} 个额外进程”的帮助
测试用例 1 以文本方式显示
  1. 3↵
  2. 1 2 9↵
以文本方式显示
  1. 15↵
1秒 64M 0

2.思路

1.错误的思路:

有的人在网上可能找到了一些参考的思路,比如贪心+快排,好吧,包括我在内,但是在这里我非常想要给各位提个醒,这道题的输入的数据有些强,快排的话我们每次都要对顺序表进行更新,所以说,虽然有着O(n*lgn)的强大的速度和效率,但是很抱歉,这道题会超时

在这里我们每次都要对数组进行实时的维护,时间复杂度计算有些麻烦,大致上应该是

O()=SUM(lg1+2*lg2+3*lg3+...n*lgn)很抱歉,学艺不精,大致应该是O(n*n*lgn)(如果错了,欢迎批评指正),所以说,这道题在输入数据过于强大的时候,超时是一定会发生的事情

2.正确的思路:

这道题我们正确的思路应该是优先队列进行处理

首先我们先来了解一下什么是优先队列,优先队列是一种高级数据结构,我们队队列中的每个数据成员都附加上一个优先级,每一次,我们都是按照优先级对队列的成员进行排序,优先级高的成员先出队列

在这里,我们可以采用两种实现方式

1.二叉堆实现优先队列

2.链表模拟优先队列

对于二叉堆的优先队列的话,我们采用对的额性质,维护最小堆,每次对堆进行递减维护

用链表的话,我们这里的思路有些相对于优化快排+贪心的策略,我的思路是每次合并完之后,我们队队列进行插入操作,这样比整体快排要好一些,但是因为数据强大,本人尝试,本体用链表插入的思路非常的慢,刚刚好AC,所以大家最好不要尝试,对于二叉堆的思路我会原因我的博客作为讲解

3.代码讲解:

优先队列实现过于简单,我们不作讲解

在这里我们着重讲解二叉堆

siftdown(i)
      t 
      flag <- 0
      while(i*2<=n and flag = 0)
           if heap[i*2]<heap[i] t <- i*2
           else t <- i
           if i*2+1 <=n and heap[i*2+1]<heap[t] t <- i*2+1
           if t != i 
                swap(i,t)
                i=t;
           else flag = 1;

在这里,我们会用到二叉树的一个性质就是,在顺序表中进行二叉树的存储的话,根节点的编号如果是n,那么做儿子存在的话编号就是2*n,右儿子存在的话就是2*n+1

建堆操作:

buildheap(i)
     for i = n/2 downto1
          siftdown(i)

这里的n/2根据上面的猜测就很好懂了

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值