- •Олимпиадные задачи и решения
- •Векторы (100 баллов)
- •Погодные условия (100 баллов)
- •Шоколадные плитки (100 баллов)
- •Работники (100 баллов)
- •Робот (100 баллов)
- •Зал Круглых Столов (100 баллов)
- •Вто (100 баллов)
- •Вишня (100 баллов)
- •Алхимия (100 баллов)
- •Цепь (100 баллов)
- •Казино (100 баллов)
- •Система уравнений (100 баллов)
- •Забавный конфуз
- •Соревнование
- •Абракадабра
- •Циферблат
- •Многоугольники
- •Квадрат
- •Лабиринт
- •Задача “Шифр”
- •Задача “Школы”
- •Последовательность
- •Автобус
- •Головоломка
- •Электронная почта
- •Виртуляндия
- •Конвейер
- •Новости
Алхимия (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.