const MaxN = 10000; type TUkol = record Odmena:integer; Termin:integer; CisloUkolu:integer; end; var Ukoly:array[1..MaxN] of TUkol; {Za co jsou nám ochotni lidi zaplatit ...} N:integer; {počet úkolů} DalsiUkol:integer; {První úkol, na který ještě nepřišla řada, tj. zatím jsme uvažovali jen vyšší časy.} VelikostHaldy:integer; Halda:array[0..MaxN-1] of TUkol; {Halda, ze které vybíráme nejvhodnější úkol pro daný čas.} VykonanychUkolu:integer; {U kolika úkolů už jistě víme, že je uděláme a kdy.} Vykonane:array[1..MaxN] of integer; {Čísla zakázek, co doopravdy uděláme.} Cas:integer; {Čas, pro který se rozhodujeme, co uděláme.} procedure NactiVstup(); var i:integer; begin readln(N); for i:=1 to N do with Ukoly[i] do begin readln(Termin,Odmena); CisloUkolu:=i; end; end; procedure VypisVysledek(); var i:integer; begin write('Nejvýhodnější pořadí je: '); for i:=VykonanychUkolu downto 1 do begin {máme je uloženy v opačném pořadí, než je je třeba vykonat} write(Vykonane[i],' '); end; writeln; end; procedure SeradDleTerminu(Min,Max:integer); {Seřadí dle termínu dokončení sestupně, tj. nejméně spěchající úkoly na konec.} {Je to obyčejný QuickSort.} var L,R:integer; Pivot:integer; Swap:TUkol; begin L:=Min; R:=Max; Pivot:=Ukoly[(Min + Max) div 2].Termin; repeat while Ukoly[L].Termin>Pivot do inc(L); while Ukoly[R].Termin= R; if R>Min then SeradDleTerminu(Min,R); if L 0) do begin {Bubláme ke kořeni} Rodic:=(Pozice - 1) div 2; if (Halda[Rodic].Odmena > Halda[Pozice].Odmena) then break; {Dál se to už nezmění ...} Swap:=Halda[Pozice]; Halda[Pozice]:=Halda[Rodic]; Halda[Rodic]:=Swap; {tak jsme vybublali o hladinu výš a všechno můžeme zopakovat} Pozice:=Rodic; end; end; procedure VyradKorenZHaldy(); {Odstraní kořen z haldy ...} var Pozice:integer; {Kde je (možná) nekonzistence v haldě...} Syn:integer; {Syn vrcholu, který právě uvažujeme} Swap:TUkol; begin dec(VelikostHaldy); {Halda se zmenší} Halda[0]:=Halda[VelikostHaldy]; Pozice:=0; repeat Syn:=Pozice * 2 + 1; if Syn >= VelikostHaldy then break; {už jsme úplně dole} if Syn+1 < VelikostHaldy then {uvažovaný vrchol má 2 syny, tak vybereme úkol s vyšší odměnou} if (Halda[Syn+1].Odmena > Halda[Syn].Odmena) then inc(Syn); if Halda[Syn].Odmena < Halda[Pozice].Odmena then break; {pokud všechny zakázky níž už jsou hůř placené, tak jsme hovovi ...} Swap:=Halda[Syn]; Halda[Syn]:=Halda[Pozice]; Halda[Pozice]:=Swap; Pozice:=Syn; {prohodíme, aby to na dané hladině bylo v pořádku a klesneme níž} until false; {ven budeme skákat pomocí breaku} end; begin NactiVstup(); if (N < 0) then begin writeln('Není co dělat.'); end else begin SeradDleTerminu(1,N); VelikostHaldy:=0; {Inicializace haldy} Cas:=Ukoly[1].Termin; {Máme setřízeno -> Tohle je maximální uvažovatelný čas} VykonanychUkolu:=0; {Zatim jsme nic neudělali} DalsiUkol:=1; {a taky jsme se ještě na nic nepodívali} while (Cas > 0) do begin {Projdeme všechny časy odzadu} while ((DalsiUkol <= N) and (Ukoly[DalsiUkol].Termin = Cas)) do begin PridejDoHaldy(Ukoly[DalsiUkol]); {přidáme do haldy všechny úkoly, které končí v tento čas} inc(DalsiUkol); end; inc(VykonanychUkolu); Vykonane[VykonanychUkolu]:=Halda[0].CisloUkolu; {nejvýhodnější je v kořeni haldy} VyradKorenZHaldy(); {a vyřadíme ho, je už hotový} if VelikostHaldy = 0 then begin if DalsiUkol > N then break {už jsme udělali všechno, co se dalo a ještě nám zbyl čas} else Cas:=Ukoly[DalsiUkol].Termin; {nějakou dobu nemáme co dělat a tak skočíme rovnou na další zajímavou položku} end else dec(Cas); {Jinak se jen posuneme zase v čase o trochu zpět} end; VypisVysledek(); end; end.