Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лк10 Переборы.DOC
Скачиваний:
42
Добавлен:
28.10.2018
Размер:
7.1 Mб
Скачать

2.3. Метод «решета»

Идея метода. Решето представляет собой метод комбинаторного программирования, который рассматривает конечное множество и исключает все элементы этого множества, не представляющие интереса. Он является логическим дополнением к процессу поиска с возвратом (backtrack), который перечисляет все элементы множества решений, представляющие интерес.

2.3.1. Решето Эратосфена

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

Числа, выделенные «жирным» шрифтом, отбрасываются.

2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

Числа, выделенные курсивом, отбрасываются.

Эратосфен - греческий математик, 275-194 гг. до нашей эры. Классическая задача поиска простых чисел в интервале [2..N] - инструмент для обсуждения метода. Объяснение строится на основе следующего рисунка и фрагмента логики.

Const N= ...;{верхняя граница интервала чисел}

Type Number=Set of 2..N;{решето, N<256}

Var S:Number;

procedure Poisk(var S:Number);

var i,j:2..N;

begin

S:=[2..N];

for i:=2 to N div 2 do

if i in S then begin

j:=i+i;

while j<=N do begin S:=S-[j];j:=j+i;end;

end;

end;

Логическим развитием задачи является ее решение при N больших 256. В этом случае необходимо ввести массив с множественным типом данных элементов.

2.3.2. Быки и коровы

(модификация задачи А.А. Суханова)

Компьютер и ребенок играют в следующую игру. Ребенок загадывает последовательность из четырех (не обязательно различных) цветов, выбранных из шести заданных. Для удобства будем обозначать цвета цифрами от 1 до 6. Компьютер должен отгадать последовательность, используя информацию, которую он получает из ответов ребенка.

Компьютер отображает на экране последовательность, а ребенок должен ответить (используя для ввода ответа клавиатуру) на два вопроса:

  • сколько правильных цветов на неправильных местах;

  • сколько правильных цветов на правильных местах.

Компьютер Ответ ребенка

1234 1 0

5156 2 1

6165 2 1

5625 1 2

5653 1 2

4655 0 4

Пример. Предположим, что ребенок загадал последовательность 4655. Один из возможных способов отгадать последовательность такой:

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

Правильный выбор структур данных - это уже половина решения. Итак, структуры данных и процедура их инициализации.

Const Pmax=6*6*6*6;

Type Post=String[4];

Var A:array[1..Pmax] of Post;

B:array[1..Pmax] of boolean;

cnt:integer;{счетчик числа ходов}

ok:boolean;{найдено решение}

procedure Init;

var i,j,k,l:integer;

begin

for i:=1 to 6 do

for j:=1 to 6 do

for k:=1 to 6 do

for l:=1 to 6 do A[(i-1)*216+(j-1)*36+(k-1)*6+l]:= Chr(i+Ord(‘0’))+Chr(j+Ord(‘0’))+Chr(k+Ord(‘0’))+Chr(k+Ord(‘0’));

for i:=1 to Pmax do B[i]:=true;

cnt:=0;ok:=false;

end;

Поясним на примере идею решета. Пусть длина последовательности равна двум, а количество цветов - четырем. Ребенок загадал 32, а компьютер спросил 24. Ответ ребенка 1 0, фиксируем его в переменных kr (1) и bk(0).

A

B

B (после анализа bk)

B (после анализа kr)

Результат

11

true

false

false

12

true

true

13

true

false

false

14

true

false

false

21

true

false

false

22

true

false

false

23

true

false

false

24

true

false

false

31

true

false

false

32

true

true

33

true

false

false

34

true

false

false

41

true

true

42

true

false

false

43

true

true

44

true

false

false

Итак, было 16 возможных вопросов, после первого осталось четыре - работа решета. Функция, реализующая анализ элемента массива А, по значениям переменных kr и bk, имеет вид:

function Pr(a,b:Post;kr,bk:integer):boolean;

var i,x:integer;

begin

{проверка по “быкам”}

x:=0;

for i:=1 to 4 do if a[i]=b[i] then inc(x);

if x<>bk then begin Pr:=false;exit;end;

{проверка по “коровам”}

x:=0;

for i:=1 to 4 do if (a[i]<>b[i]) and (Pos(b[i],a)<>0) then inc(x);

if x<>kr then begin Pr:=false;exit;end;

Pr:=true;

end;

Логика - “сделать отсечение” по значению хода h.

procedure Hod(h:Post);

var i,kr,bk:integer;

begin

inc(cnt);write(cnt:2,’.’,h,’-’);

readln(kr,bk);

if bk=4 then begin ok:=true;<вывод результата>;end

else for i:=1 to Pmax do if B[i] and Not Pr(A[i],h,kr,bk) then B[i]:=false;

end;

Общая логика.

.....

begin

clrscr;

init;

hod(‘1223’);

while not ok do begin

выбор очередного хода из А

hod(h);

end;

end.

Дальнейшая работа с задачей требует ответа на следующие вопросы: