zoukankan      html  css  js  c++  java
  • 合并果子 (codevs 1063) 题解

    【问题描述】

        在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。多多决定把所有的果子合成一堆。


        每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。


        因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。


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

    【样例输入】

         3 
        1 2 9

    【样例输出】

        15

    【解题思路】

         本题为NOIP2004提高组第二题,有两种方法可以解答。一个是贪心+堆,另一个是双排序队列。

         先来说说贪心+堆。

         首先,建一个小根堆,这样就保证根为最小的,取出根并维护小根堆,再取出根并维护小根堆,这样就得到了我们需要的结果,把结果插入堆中并维护,反复这个操作n-1次即可。详见代码。

        然后是队列。

        首先将果子排序,构成一个序列,将最前面的两堆果子取出,放入另一个队列,接下来,就只要判断之后应该取哪两堆,要么取最先的队列中的前两个,要么取新的队列中的前两个,要么取两个队列最前面的一个,然后再放到新的队列中,这样就能保证新的队列必是一个排序好的队列。将新的队列中的每个数加起来便是结果。

    【代码实现】

     1 var a:array[0..10000] of longint;
     2     i,n,k,ans,n1:longint;
     3 procedure swap(var a,b:longint);
     4 var y:longint;
     5 begin
     6  y:=a;a:=b;b:=y;
     7 end;
     8 procedure sift(i,m:longint);
     9 var k:longint;
    10 begin
    11  a[0]:=a[i];
    12  k:=2*i;
    13  while k<=m do
    14   begin
    15    if (k<m)and(a[k]<a[k+1]) then
    16     inc(k);
    17    if a[0]<a[k] then
    18     begin
    19      a[i]:=a[k];
    20      i:=k;
    21      k:=i*2;
    22     end
    23    else
    24     k:=m+1;
    25   end;
    26  a[i]:=a[0];
    27 end;
    28 procedure heapsort;
    29 var j:longint;
    30 begin
    31  for j:=n div 2 downto 1 do
    32   sift(j,n);
    33  for j:=n downto 2 do
    34   begin
    35    swap(a[1],a[j]);
    36    sift(1,j-1);
    37   end;
    38 end;
    39 function deletemin:longint;
    40 var i,pos:longint;
    41 begin
    42  i:=1;
    43  deletemin:=a[1];
    44  a[1]:=a[n1];
    45  dec(n1);
    46  while 2*i<=n1 do
    47   begin
    48    pos:=2*i;
    49    if (pos<n1)and(a[pos+1]<a[pos]) then
    50     inc(pos);
    51    if a[i]>a[pos] then
    52     begin
    53      swap(a[i],a[pos]);
    54      i:=pos;
    55     end
    56    else
    57     break;
    58   end;
    59 end;
    60 procedure insert(k:longint);
    61 var i:longint;
    62 begin
    63  inc(n1);
    64  a[n1]:=k;
    65  i:=n1;
    66  while (i div 2>0)and(a[i div 2]>k) do
    67   begin
    68    swap(a[i],a[i div 2]);
    69    i:=i div 2;
    70   end;
    71 end;
    72 begin
    73  readln(n);
    74  for i:=1 to n do
    75   read(a[i]);
    76  heapsort;
    77  n1:=n;
    78  for i:=1 to n-1 do
    79   begin
    80    k:=deletemin;
    81    k:=k+deletemin;//取出根并维护
    82    ans:=ans+k;
    83    insert(k);//插入结果并维护
    84   end;
    85  writeln(ans);
    86 end.
     1 var old,new:array[0..10000] of longint;
     2     i,n,fo,fn,rn,ans:longint;
     3 procedure swap(var i,j:longint);
     4 var y:longint;
     5 begin
     6  y:=i;i:=j;j:=y;
     7 end;
     8 procedure sift(i,m:longint);
     9 var k:longint;
    10 begin
    11  old[0]:=old[i];
    12  k:=2*i;
    13  while k<=m do
    14   begin
    15    if (k<m)and(old[k]<old[k+1]) then
    16     inc(k);
    17    if old[0]<old[k] then
    18     begin
    19      old[i]:=old[k];
    20      i:=k;
    21      k:=2*i;
    22     end
    23    else
    24     k:=m+1;
    25   end;
    26  old[i]:=old[0];
    27 end;
    28 procedure heapsort;
    29 var j:longint;
    30 begin
    31  for j:=n div 2 downto 1 do
    32   sift(j,n);
    33  for j:=n downto 2 do
    34   begin
    35    swap(old[1],old[j]);
    36    sift(1,j-1);
    37   end;
    38 end;
    39 begin
    40  readln(n);
    41  for i:=1 to n do
    42   read(old[i]);
    43  heapsort;//这个排序可以是堆排,二叉排序树,快排等等,因为我今天复习到堆,就用堆排了
    44  fo:=3;
    45  new[1]:=old[1]+old[2];
    46  ans:=new[1];
    47  fn:=1;
    48  rn:=1;
    49  repeat
    50   if (old[fo+1]<>0)and(old[fo+1]<new[fn])then
    51    begin
    52     inc(rn);
    53     new[rn]:=old[fo]+old[fo+1];
    54     ans:=ans+new[rn];
    55     inc(fo,2);
    56    end
    57    else
    58     if (new[fn+1]<>0)and(new[fn+1]<old[fo]) then
    59      begin
    60       inc(rn);
    61       new[rn]:=new[fn]+new[fn+1];
    62       ans:=ans+new[rn];
    63       inc(fn,2);
    64      end
    65     else
    66      if (old[fo]=0)and(new[fn+1]<>0) then
    67       begin
    68        inc(rn);
    69        new[rn]:=new[fn]+new[fn+1];
    70        ans:=ans+new[rn];
    71        inc(fn,2);
    72       end
    73      else
    74       begin
    75        inc(rn);
    76        new[rn]:=new[fn]+old[fo];
    77        ans:=ans+new[rn];
    78        inc(fo);
    79        inc(fn);
    80       end;
    81  until (old[fo+1]=0)and(new[fn+1]=0);
    82  writeln(ans);
    83 end.
  • 相关阅读:
    windows系统-web渗透工具-AWVS
    PHP.9-HTML+CSS(三)-CSS样式
    PHP.10-PHP实例(一)-简单的计算器
    PHP.8-HTML+CSS(二)-HTML详解
    PHP.7-HTML+CSS(一)-HTML语法、常用字符实体、颜色代码
    noip2018 铺设道路
    noip2018游记
    luogu题解P1967货车运输--树链剖分
    ZROI-Day2比赛解题报告
    ZROI Day1 比赛解题报告
  • 原文地址:https://www.cnblogs.com/PengBoLiuXu/p/4501392.html
Copyright © 2011-2022 走看看