木板

《高级数据结构》p95 例3-4


【算法提点】


朴素想法

贪心的算法,每次插入木板使木板右端尽量靠左。

设每次插入木板后最右端位置为pre

考虑每一块木板右端的值=max(p[i],pre+l[i])

如果max=p[i]

|      -----.  (----为木板   .为钉子)

如果max=pre+l[i]

|--------.----   (----为木板   .为钉子)

每一次找最小的max,就是把所有未插入木板扫一遍,时间复杂度是N^2的



优化

对木板进行分类

对于第一类木板——每一块max=p[i]的木板i,在pre向右变大的过程中,max有可能会变成pre+l[i],变成第二类木板

对于第二类木板——每一块max=pre+l[i]的木板i,由于pre在不断变大,p[i]不变,所以第二类木板的pre+l[i]恒大于p[i],所以原本就在第二类的木板和第一类变成第二类的木板不可能变回第一类

min(max(p[i],pre+l[i]))=min(第一类木板最小值(最小值的木板要能放,即p[i]>=pre),第二类木板最小值(最小值的木板要能放,即p[i]>=pre))

于是用堆来维护两类木板,每类木板取最小值时都要判断能不能放,若不能放则丢掉直到找到能放的或堆空;第一类木板在取最小值时如果发现pre+l[i]>p[i]就把它放到第二类中,直到取出p[i]>pre+l[i]!!!

!!!第一类取出满足的一个木板后第一类中可能仍然有剩下的要变成第二类的木板,没有必要本次操作对他们处理

              证明:对于仍在第一类堆中不是最小的但要变成第二类的木板,设该木板为a(a也表示该木板最右端位置)

                        对于第一类堆中最小的(不要变成第二类的木板),设该木板为b(b也表示该木板最右端位置)

                        满足pre+l[a]>p[a] p[a]>p[b]

                        所以a>b

                        设第二堆中最小木板为c(c也表示该木板最右端位置)

                        若a<c 因为b<a 所以b一定min(第一类木板最小值,第二类木板最小值)

                        若a>c 则min(max(p[i],pre+l[i]))=(b,c)

                        所以a不影响结果,所以本次操作把不把它们变成第二类都没事

重复放置操作,当第一类和第二类木板都空时,就结束放置。



优化后时间复杂度

这样算法的时间复杂度是n*log2(n)最多n此操作,每一次操作维护两个堆都是log2(n)的,其中第一类变成第二类的维护总复杂度最多为n*log2(n)

【代码】

代码只过了样例,其他数据没有测试过!

//2016-4-9
//God save princess
//By Shui'Bing ICEE
const
  maxn=200000;
var
  n,pre,i,l1,l2,min1,min2,s:longint;
  l,p,heap1,heap2:array[0..maxn] of longint;
  procedure put1(x:longint);
var
  son,temp:longint;
begin
  inc(l1);
  heap1[l1]:=x;
  son:=l1;
  while (son<>1) and (p[heap1[son]]<p[heap1[son div 2]]) do
    begin
      temp:=heap1[son];
      heap1[son]:=heap1[son div 2];
      heap1[son div 2]:=temp;
      son:=son div 2;
    end;
end;

  procedure put2(x:longint);
var
  son,temp:longint;
begin
  inc(l2);
  heap2[l2]:=x;
  son:=l2;
  while (son<>1) and (l[heap2[son]]<l[heap2[son div 2]]) do
    begin
      temp:=heap2[son];
      heap2[son]:=heap2[son div 2];
      heap2[son div 2]:=temp;
      son:=son div 2;
    end;
end;

  procedure get1;
var
  fa,son,temp:longint;
begin
  heap1[1]:=heap1[l1];
  heap1[l1]:=0;
  dec(l1);
  fa:=1;
  while fa*2<=l1 do
    begin
      if (fa*2+1>l1) or (p[heap1[fa*2]]<p[heap1[fa*2+1]])
      then son:=fa*2
      else son:=fa*2+1;
      if p[heap1[fa]]>p[heap1[son]]
      then begin
             temp:=heap1[fa];
             heap1[fa]:=heap1[son];
             heap1[son]:=temp;
             fa:=son
           end
       else break;
    end;
end;

  procedure get2;
var
  fa,son,temp:longint;
begin
  heap2[1]:=heap2[l2];
  heap2[l2]:=0;
  dec(l2);
  fa:=1;
  while fa*2<=l2 do
    begin
      if (fa*2+1>l2) or (l[heap2[fa*2]]<l[heap2[fa*2+1]])
      then son:=fa*2
      else son:=fa*2+1;
      if l[heap2[fa]]>l[heap2[son]]
      then begin
             temp:=heap2[fa];
             heap2[fa]:=heap2[son];
             heap2[son]:=temp;
             fa:=son
           end
       else break;
    end;
end;

begin
  read(n);
  pre:=maxlongint;
  for i:=1 to n do
    begin
      read(l[i],p[i]);
      if p[i]<pre
      then pre:=p[i];
    end;
  l1:=0;
  l2:=0;
  for i:=1 to n do
    begin
      if p[i]<>pre
      then begin
             if pre+l[i]>=p[i]
             then put2(i)
             else put1(i);
           end;
    end;
  s:=1;
  while 1+1=2 do
    begin
      min1:=maxlongint;
      while l1>0 do
        begin
          if p[heap1[1]]<pre
          then begin
                 get1;
                 continue;
               end;
          if l[heap1[1]]+pre>=p[heap1[1]]
          then begin
                 put2(heap1[1]);
                 get1;
               end
          else begin
                 min1:=p[heap1[1]];
                 break;
               end;
        end;
      min2:=maxlongint;
      while l2>0 do
        begin
          if p[heap2[1]]<pre
          then begin
                 get2;
                 continue;
               end
          else begin
                 min2:=l[heap2[1]]+pre;
                 break;
               end;
        end;
      if (min1=maxlongint) and (min2=maxlongint)
      then break;
      inc(s);
      if min1<min2
      then begin
             pre:=min1;
             get1;
           end
      else if min1>min2
           then begin
                  pre:=min2;
                  get2;
                end
           else begin
                  pre:=min1;
                  if p[heap1[1]]<p[heap2[1]]
                  then get1
                  else get2;
                end;
    end;
  writeln(s);
end.


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值