《高級數據結構》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.