type TIntArray = array[1..1000000] of LongInt; PIntArray = ^TIntArray; procedure loadData(var Bankovky: PIntArray; var N: LongInt); begin { tahle procedůra vytvoří pole Bankovky potřebné délky a načte do něj data, také inicializuje proměnnou N } end; { Spočítá a vrátí celkový součet všech prvků v poli Bankovky - tj. celkovou hodnotu všech bankovek } function soucet(Bankovky: PIntArray; N: LongInt): LongInt; var res: LongInt; begin res := 0; while N > 0 do begin res := res + Bankovky^[N]; dec(N); end; soucet := res; end; { Hlavní algoritmus - zjistí, jak dosáhnout všech možných součtů (naplní pole "Vybrane") } procedure spoctiSoucty(Bankovky: PIntArray; N: LongInt; Vybrane: PIntArray; Sum: LongInt); var i, max, item: LongInt; begin for i := 1 to Sum do Vybrane^[i] := 0; { inicializujeme si pole "Vybrane" } max := 0; for item := 1 to N do begin { zkusíme všechny bankovky } if Bankovky^[item] > Sum then Exit; { nalezli jsme bankovku,která je cennější,než půlka...máme smůlu } for i := max downto 1 do { postupně prověřuji všěchny možné součty } if (Vybrane^[i] > 0) and (i + Bankovky^[item] <= Sum) and (Vybrane^[i + Bankovky^[item]] = 0) then Vybrane^[i + Bankovky^[item]] := item; { umím součet i => umím také součet i + nová bankovka } if Vybrane^[ Bankovky^[item] ] = 0 then Vybrane^[ Bankovky^[item] ] := item; max := max + Bankovky^[item]; { upravím maximální součet, který jsem doposud viděl } if (max > Sum) then begin { ale stačí mi jen součty do velikosti částky, kterou hledám } max := Sum; if (Vybrane^[Sum] > 0) then Exit; { pokud jsem našel způsob, jak dostat hledanou částku, končím } end; end; end; { Vytahá z pole Vybrane bankovky a vypíše je na výstup } procedure zapisVysledky(Bankovky: PIntArray; N: LongInt; Vybrane: PIntArray; Sum: LongInt); var i: LongInt; begin if (Vybrane^[Sum] = 0) then begin { neexistuje způsob, jak složit součet velikosti Sum } writeln('Bankovky nelze rozdělit na polovinu.'); Exit; end; i := Sum; { i představuje částku, kterou je tě zbývá vypsat } while i > 0 do begin writeln(Vybrane^[i]); { vypíšeme vybranou bankovku } i := i - Bankovky^[ Vybrane^[i] ]; { zmenšíme akt. částku o právě vypsanou bankovku } end; end; var N, Sum: LongInt; Bankovky, Vybrane: PIntArray; begin loadData(Bankovky, N); Sum := soucet(Bankovky, N); if (Sum mod 2 = 0) then begin Sum := Sum div 2; { chceme vybrat bankovky, jejich součet je právě polovina celkového součtu } GetMem(Vybrane, Sum * sizeof(LongInt)); spoctiSoucty(Bankovky, N, Vybrane, Sum); { hlavní algoritmus } zapisVysledky(Bankovky, N, Vybrane, Sum); { vytaháme výsledky z pole "Vybrane" a vypí eme je } end else writeln('Bankovky nelze rozdělit.'); { je-li celkový součet lichý, určitě nepůjde rozdělit na dvě stejné části } end.