《高级数据结构》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.