Скачиваний:
35
Добавлен:
01.05.2014
Размер:
1.1 Mб
Скачать

Алхимия (100 баллов)

Известны K видов веществ и N типов алхимических реакций. Каждая реакция по набору входных веществ продуцирует набор выходных. Проведение каждой реакции требует фиксированного времени. Любые вещества, полученные в результате реакций, можно выделять в чистом виде для отдельного использования. Каждого вещества всегда достаточно для любого использования. Вещество, полученное в результате только что закончившейся реакции, можно сразу же использовать в других реакциях. Реакции могут проходить одновременно.

Задание

Напишите программу ALCHEMY, которая по информации об известных веществах и реакциях определяет за какое наименьшее время можно получить целевое вещество.

Входные данные

Первая строка входного файла ALCHEMY.DAT содержит четыре целых числа: K (3≤K≤250) — количество веществ, N (3≤N≤500) — количество реакций, M (1≤M<K) — количество имеющихся сначала веществ, а также номер целевого вещества.

Далее следуют N блоков, которые описывают реакции. Каждый блок состоит из трех строк: первая содержит натуральное число — время, необходимое для проведения реакции, вторая строка — количество веществ, которые вступают в реакцию, и перечень этих веществ, третья строка — количество веществ, которые образовываются в результате реакции, и их перечень.

Вещества, имеющиеся сначала, имеют номера от 1 до M, а все остальные — от M+1 до K. Сумма времен проведения всех реакций не превышает 2∙109.

Выходные данные

Единственная строка выходного файла ALCHEMY.SOL должна содержать целое число — найденное минимальное время, за которое может быть получено целевое вещество.

Если получить целевое вещество невозможно, единственная строка выходного файла должна содержать число -1.

Для приведенного примера входных данных, целевое вещество 4 можно получить, если на протяжении первых трех единиц времени провести реакцию 2, а после этого на протяжении двух единиц времени провести реакцию 3. Таким образом, за 5 единиц времени будет получено требуемое вещество.

Пример входных и выходных данных

ALCHEMY.DAT

ALCHEMY.SOL

4 3 1 4

8

1 1

1 4

3

1 1

2 2 3

2

2 1 3

1 4

5

{ Problem: ALCHEMY}

const MAX_EL=250;

MAX_EQ=500;

INFTY=$7FFFFFFF;

type PArr=^TArr;

TArr=array[0..MAX_EL-1] of byte;

TElSet=record

Num:integer;

els:PArr;

end;

TEq=record

time:integer;

left,right:TElSet;

end;

TReactOut=record

eq_:integer;

tim_:longint

end;

var fv:text;

i,j,N_El,N_Eq,num_unused:integer;

EQs:array[1..MAX_EQ] of TEq;

used:array[1..MAX_EQ] of boolean;

_1st_non_2:array[1..MAX_EQ] of integer;

{while spreading - number of the reaction which gave the elem;

while backing - positive number means we may need push reaction to list,

negative - it's already pushed}

got_time:array[1..MAX_EL] of longint;

{time when the elem got}

status:array[1..MAX_EL] of byte;

{0 - sleeping, 1 - waked up, 2 - killed}

N_pres:integer;

e,goal_el:integer;

curr_time,min_waked:longint;

min_waked_idx:integer;

got_new:boolean;

need_reacts:array[0..MAX_EQ] of TReactOut;

num_reacts:integer;

Eq_Out:array[1..MAX_EQ] of boolean;

procedure read_eq(var fv:text; var eq:TEq);

var i:integer;

Begin

readln(fv,eq.time);

read(fv,eq.left.num);

GetMem(eq.left.els,eq.left.num*sizeof(integer));

for i:=0 to eq.left.num-1 do

read(fv,eq.left.els^[i]);

readln(fv);

read(fv,eq.right.num);

GetMem(eq.right.els,eq.right.num*sizeof(integer));

for i:=0 to eq.right.num-1 do

read(fv,eq.right.els^[i]);

readln(fv);

End;

function all_present(e:integer):boolean;

var i:integer;

Begin

i:=_1st_non_2[e];

while (i<=eqs[e].left.num) and (status[eqs[e].left.els^[i-1]]=2) do

i:=i+1;

if (i<=eqs[e].left.num) and (status[eqs[e].left.els^[i-1]]<>2) then begin

_1st_non_2[e]:=i;

all_present:=false

end else

all_present:=true;

End;

BEGIN

assign(fv,'alchemy.dat'); reset(fv);

readln(fv,N_El,N_Eq,N_pres,goal_el);

for i:=1 to N_El do begin

got_time[i]:=INFTY; status[i]:=0;

end;

for e:=1 to N_pres do begin

got_time[e]:=0; status[e]:=2;

end;

num_unused:=N_eq;

for i:=1 to N_Eq do begin

read_eq(fv,eqs[i]);

used[i]:=false;

_1st_non_2[i]:=1;

end;

close(fv);

(*

initialization complete, starting processing

*)

curr_time:=0;

repeat

for i:=1 to n_eq do

if not used[i] and all_present(i) then begin

for j:=0 to eqs[i].right.num-1 do begin

e:=eqs[i].right.els^[j];

if (status[e]=0) or ((status[e]=1)and(got_time[e]>curr_time+eqs[i].time)) then begin

status[e]:=1;

got_time[e]:=curr_time+eqs[i].time;

end;

end;

used[i]:=true;

num_unused:=num_unused-1;

end;

min_waked:=INFTY;

for i:=1 to N_el do begin

if (status[i]=1) and (got_time[i]<min_waked) then

min_waked:=got_time[i];

end;

got_new:=min_waked<INFTY;

if got_new then begin

for i:=1 to N_el do

if (status[i]=1) and (got_time[i]=min_waked) then begin

status[i]:=2;

curr_time:=min_waked;

end;

end;

until (status[goal_el]=2) or (not got_new) or (num_unused=0);

if num_unused=0 then begin

for i:=1 to N_El do if status[i]=1 then status[i]:=2;

end;

(*

main processing complete, starting outputting (and restoring schedule)

*)

assign(fv,'alchemy.sol'); rewrite(fv);

if status[goal_el]<>2 then

writeln(fv,'-1')

else begin

writeln(fv,got_time[goal_el]);

end;

close(fv);

END.