Второй способ решения — перебор расстановок.
11 класс, углублённый уровень.
Перебор вложенными циклами вы уже знаете. Сегодня — способ, при котором программа сама подбирает, какая переменная стоит в каком столбце. Приём тот же, что в задании 1: перебрать все расстановки и проверить каждую.
Функция F задана выражением F = ((x → y) ∨ (z ≡ x)) ∧ (w → z). Дан фрагмент её таблицы истинности — три строки, и не подписано, какому столбцу какая переменная досталась.
| ? | ? | ? | ? | F |
|---|---|---|---|---|
| 0 | 0 | 1 | 1 | 1 |
| 0 | 0 | 1 | 0 | 0 |
| 0 | 1 | 1 | 1 | 0 |
Ответ — буквы в порядке столбцов, подряд и без разделителей.
for x in range(2):
for y in range(2):
for z in range(2):
for w in range(2):
F = ((x <= y) or (z == x)) and (w <= z)
if F == 1:
print(x, y, z, w)
Программа печатает все наборы, на которых F = 1, — а дальше человек глазами прикладывает их к строкам фрагмента.
Ничего лишнего знать не надо: четыре цикла и условие.
Самую трудную часть — сопоставление столбцов — делает человек. На пропусках в таблице это почти безнадёжно.
Вся идея второго способа — в двух строках:
for p in permutations('xyzw'):
p = ''.join(p)
permutations из модуля itertools выдаёт все 24
расстановки букв, join склеивает каждую в строку:
'xyzw', 'xywz', … 'zwxy'. Каждая —
гипотеза: «в первом столбце z, во втором w, в третьем x, в четвёртом y».
Ровно как расстановка букв по пунктам в задании 1.
indexПусть гипотеза p = 'zwxy', а строка таблицы
row = (0, 0, 1, 1, 1) — четыре значения и пятым F.
| номер (с нуля) | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
буква p | z | w | x | y | F |
значение row | 0 | 0 | 1 | 1 | 1 |
p.index('x') 2 # номер места буквы x в строке p
row[p.index('x')] 1 # значение из этого столбца
index отвечает на вопрос «в каком столбце стоит x» — при
любой гипотезе. Одна строка, и значение x найдено.
x = row[p.index('x')]
y = row[p.index('y')]
z = row[p.index('z')]
w = row[p.index('w')]
F = ((x <= y) or (z == x)) and (w <= z)
После четырёх строк x, y, z,
w — обычные переменные Python со значениями из этой строки
таблицы. Выражение F пишется прямо, как в условии.
def и вызовов функции: значения уже лежат в
переменных, функция не нужна.
index: y = row[p.index('x')]. Две переменные
читают один столбец, и программа врёт молча.
x, y, z, w = [row[p.index(v)] for v in 'xyzw']
Справа — список из четырёх значений, по одному на букву из
'xyzw'; слева они распаковываются в четыре переменные.
Порядок букв в строке и порядок имён слева обязаны совпадать. Три
переменные — x, y, z и 'xyz'.
table = [(0, 0, 1, 1, 1),
(0, 0, 1, 0, 0),
(0, 1, 1, 1, 0)]
Таблица переписывается с листа как есть: строка за строкой, вместе
со значением F. F — пятое число, а номера считаются с нуля, значит
row[4].
if F != row[4]:
ok = False
Посчитали F по гипотезе — сравнили с F на листе. Не сошлось хотя бы в одной строке — гипотеза не та.
index, а F лежит в
row[3].
ok = True
for row in table:
x = row[p.index('x')]
y = row[p.index('y')]
z = row[p.index('z')]
w = row[p.index('w')]
F = ((x <= y) or (z == x)) and (w <= z)
if F != row[4]:
ok = False
if ok:
print(p)
ok взводится в True для каждой расстановки
заново; строки таблицы могут его только сбросить. Прошла все строки —
печатаем: p уже строка, ответ выходит в нужном виде.
from itertools import *
table = [(0, 0, 1, 1, 1), (0, 0, 1, 0, 0), (0, 1, 1, 1, 0)]
for p in permutations('xyzw'):
p = ''.join(p)
ok = True
for row in table:
x = row[p.index('x')]
y = row[p.index('y')]
z = row[p.index('z')]
w = row[p.index('w')]
F = ((x <= y) or (z == x)) and (w <= z)
if F != row[4]:
ok = False
if ok:
print(p)
zwxy
table и
F. Остальное переносится без правок.
<=| A | B | A → B | A ≤ B |
|---|---|---|---|
| 0 | 0 | 1 | 1 |
| 0 | 1 | 1 | 1 |
| 1 | 0 | 0 | 0 |
| 1 | 1 | 1 | 1 |
¬A → not A
A ∧ B → A and B
A ∨ B → A or B
A → B → A <= B
A ≡ B → A == B
not x <= y Python читает как
not (x <= y), а x <= y == z — вообще как
цепочку сравнений. Лишние скобки не мешают, пропущенные — меняют смысл.
not (w <= x). Переписывая, скобки добавляем, а
не убираем.
F получается True или False, а на листе 1
или 0. Сравнение F != row[4] это понимает:
True == 1, False == 0.
Демоверсия 2024, базовый уровень.
F = (x ∧ ¬y) ∨ (y ≡ z) ∨ ¬w
| ? | ? | ? | ? | F |
|---|---|---|---|---|
| 0 | 0 | 0 | ||
| 1 | 0 | 0 | 0 | |
| 1 | 0 | 1 | 0 |
Пустых клеток четыре. Значит и заполнений — 2⁴ = 16.
productfrom itertools import *
for a1, a2, a3, a4 in product([0, 1], repeat=4):
table = [(a1, a2, 0, 0, 0), (1, 0, a3, 0, 0), (1, 0, 1, a4, 0)]
if len(table) == len(set(table)):
for p in permutations('xyzw'):
p = ''.join(p)
ok = True
for row in table:
... # те же строки, что и раньше
if ok:
print(p)
wzyx
product([0, 1], repeat=4) — все 16 наборов из нулей и
единиц. Пропуски просто становятся переменными цикла, а в
table на их месте стоят a1…a4.
if len(table) == len(set(table)):
for p in permutations('xyzw'):
...
В условии сказано: строки фрагмента различны. Заполнив пропуски наугад, можно получить две одинаковые строки — с таким вариантом дальше работать нельзя, перестановки для него не перебираем.
set(table) — множество, повторы в нём схлопываются.
Длины разошлись — значит повтор был. Что в строках есть ещё и F, не
мешает: одинаковые строки одинаковы и вместе с F.
| Ошибка | Что получится |
|---|---|
x < y вместо x <= y |
импликация становится неверной при x = y = 1 |
y = row[p.index('x')] |
две переменные из одного столбца — программа врёт молча |
row[3] вместо row[4] |
F сравнивается не с F, а с последним столбцом переменных |
permutations('xyz') при четырёх переменных |
ValueError: p.index('w') не находит букву |
ok = False в начале |
ничего не печатается: сбросить флаг можно, взвести — нечем |
забыть set(table) |
лишние ответы там, где ответ один |
from itertools import * забыт |
NameError: permutations не определено |
А вот пропущенное
p = ''.join(p) ошибкой не считается: index на
кортеже работает так же, а ответ вы всё равно вписываете руками — кортеж
на экране читается не хуже.
from itertools import *
for a1, a2, a3 in product([0, 1], repeat=3):
table = [(a1, 0, 1, a2, 0), (1, 1, a3, 0, 0), (0, 1, 1, 1, 0)]
if len(table) == len(set(table)):
for p in permutations('xyzw'):
p = ''.join(p)
ok = True
for row in table:
x = row[p.index('x')]
y = row[p.index('y')]
z = row[p.index('z')]
w = row[p.index('w')]
F = ... # выражение: → это <=, ≡ это ==
if F != row[4]:
ok = False
if ok:
print(p)
Пропусков на ЕГЭ бывает пять или семь: меняется только число
a1…a7 и repeat. Всё остальное
переносится без правок.
Открывайте практикум.
Шесть задач. Первые четыре — про то, как этот код устроен: их считают
в голове. Два задания 2 решайте программой: набрали один раз — дальше
меняете только table и строку с F.