Решение
Тема: перебор, моделирование
Сложность: средняя
В задаче требуется найти такую перестановку
`Q_i` чисел от 1 до 7, которая дает минимальный суммарный недосып.
Сначала рассмотрим способы гнерации всех перестановок чисел от 1 на 7. На 1-е место можно поставить любое из 7 чисел, на 2-е – одно из оставшихся 6 чисел, на 3-е – одно из оставшихся 5 чисел, и т.д. Соответствующая часть программы может выглядеть так:
var q:array [1..7] of integer;
...
for q[1]:=1 to 7 do
for q[2]:=1 to 7 do
if q[2]<>q[1] then
for q[3]:=1 to 7 do
if (q[3]<>q[1]) and (q[3]<>q[2]) then
for q[4]:=1 to 7 do
if (q[4]<>q[1]) and (q[4]<>q[2]) and (q[4]<>q[3]) then
for q[5]:=1 to 7 do
if (q[5]<>q[1]) and (q[5]<>q[2]) and
(q[5]<>q[3]) and (q[5]<>q[4]) then
for q[6]:=1 to 7 do
if (q[6]<>q[1]) and (q[6]<>q[2]) and
(q[6]<>q[3]) and (q[6]<>q[4]) and (q[6]<>q[5]) then
for q[6]:=1 to 7 do
if (q[7]<>q[1]) and (q[7]<>q[2]) and
(q[7]<>q[3]) and (q[7]<>q[4]) and
(q[7]<>q[5]) and (q[7]<>q[6]) then
{В массиве q получили перестановку}
Для упрощения программы можно завести массив флажков, в котором отмечать те числа, которые уже используются, и организовать выполнение вложенных циклов с помощью рекурсии:
var q:array [1..7] of integer;
used:array [1..7] of boolean;
i:integer;
procedure rec(i:integer);
var j:integer;
begin
if i>7 then
begin
{В массиве q получили перестановку}
exit;
end
for j:=1 to 7 do
if not used[j] then
begin
used[j]:=true;
q[i]:=j;
rec(i+1);
used[j]:=false;
end;
end;
...
for i:=1 to 7 do
used[i]:=false;
rec(1);
Существует немного более сложный, но более эффективный способ генерации перестановок. Генерация начинается с последовательности 1, 2, …, 7. На
`i`-м шаге число, стоящее на
`i`-м месте меняется с одним из чисел, стоящих на местах с
`i`-го по 7-ое и рекурсивно выполняется (
`i`+1)-й шаг. По окончании шага нужно восстановить состояние массива на начало шага.
var q:array [1..7] of integer;
i:integer;
procedure rec(i:integer);
var j,t:integer;
begin
if i>7 then
begin
{В массиве q получили перестановку}
exit;
end
for j:=i to 7 do
begin
t:=q[i];
q[i]:=q[j];
q[j]:=t;
rec(i+1);
end;
t:=q[i];
for j:=i+1 to 7 do
q[i-1]:=q[i];
q[7]:=t;
end;
...
for i:=1 to 7 do
q[i]:=i;
rec(1);
После получения перестановки нужно промоделировать, как будут просыпаться гномы. В массив
`S_i` поместим на сколько минут раньше проснется гном, спящий на
`i`-м месте.
for i:=1 to 7 do
s[q[i]]:=c[i]*abs(p[i]-q[i]);
Когда гном просыпается он будит также всех гномов, лежащих ближе к выходу. Гном не может спать дольше гномов, спавших глубже в штреке, поэтому при просмотре массива
`S_i` справа налево находим максимум. Суммарное время недосыпа можно вычислить так:
sum:=0;
m:=0;
for i:=7 downto 1 do
begin
if s[i]>m then
m:=s[i];
sum:=sum+m;
end;
Среди сумм недосыпа находим минимум и запоминаем перестановку, при которой он достигается. После обработки всех перестановок выводим перестановку, минимизирующую суммарный недосып.