Вы находитесь на странице: 1из 10

Міністерство освіти і науки України

Національний технічний університет України


«Київський політехнічний інститут»
Факультет менеджменту та маркетингу
Кафедра математичного моделювання економічних систем

Лабораторна робота № 2
з дисципліни «Системи штучного інтелекту в
моделюванні економіки»
на тему: «Евристичні алгоритми»

Виконав:
Студентка групи УК-71
Юхименко Ганна Костянтинівна
Прийняв:
Рисцов Ігор Костянтинович

Київ – 2020
2.3.1Т. Из каких позиций достижима финальная позиция для игры восемь,
показанная на рис. 1.1 справа? Указание: Используйте понятие числа инверсий
позиции.

Эта задача имеет 9! = 362 880 возможных позиций, из которых половина являются


достижимыми из начального состояния.
Целевое состояние не имеет инверсий (перед фишками с большим номером стоят
фишки с меньшими номерами). Так как количество инверсий для начального состояния (16)
четное число, то можно достичь целевого состояния. Инверсия считается достижимой только
в том случае, если она четная. Таким образом целевое состояние достигается из половины
позиций.
2.3.2У. Сколькими способами можно расставить восемь ферзей на шахматной
доске так, чтобы на каждой вертикали было по одному ферзю?
Аналогичную проблему имеет задача о 8 ферзях. К тому же, накладываются
дополнительные условия: каждый из ферзей не должен быть атакован другими. Таким
образом, решение, полученное в результате, выглядит как размещение на каждой вертикали
шахматной доски одного ферзя

Задача о восьми ферзях является примером общей задачи о n ферзей: задачи


размещения n ферзей на шахматной доске размером n × n, которая имеет решения для n = 1
или n ≥ 4.
Решение задачи в две строки кода  :
from itertools import permutations as p
print(*('\n'.join(' -' * i + ' Q' + ' -' * (7 - i) for i in v) for v in p(range(8)) if len({v[i] + i for i
in range(8)}) == 8 == len({v[i] - i for i in range(8)})), sep='\n\n')
Он нам выдает 92 решения. Если отбросить похожие композиции с точностью до
отражения (отражение позиции на шахматной доске) и вращения (вращение позиции на
шахматной доске), останется 12 уникальных решений:

2.3.3К. Запрограммируйте алгоритм 2.1 и проверьте его на графе автомата,


который задан следующей таблицей. Здесь через наклонную черту для каждого
перехода указано следующее состояние и стоимость перехода. Состояние 1 является
начальным, а состояние 4 – финальным.

def deikstra(f, c, s0, f0):


global tree, cost, Max
Max = 600
if s0 == f0:
return 0
m = len(f)
n = len(f[1])
v = [i for i in range(n)]
cost = [Max for i in range(n)]
tree = [0 for i in range(n)]
cost[s0] = 0
for j in range(m):
t = f[j][s0]
if cost[t] > c[j][s0]:
cost[t] = c[j][s0]
tree[t] = [s0, chr(97 + j)]
v.remove(s0)
while len(v) > 0:
s = v[0]
for t in v:
if cost[t] < cost[s]:
s=t
if s == f0:
return Sol(s0, f0)
if cost[s] == Max:
return 'failure'
v.remove(s)
for j in range(m):
t = f[j][s]
if cost[t] > cost[s] + c[j][s]:
tree[t] = [s, chr(97 + j)]
cost[t] = cost[s] + c[j][s]
def Sol(s, f):
global tree, cost
L = [f]
t=f
while t != s:
L.insert(0, tree[t])
t = tree[t][0]
return cost[f], L
f=[
[1, 2, 4, 2, 3],
[4, 2, 0, 0, 3]
]
c=[
[10, 50, 10, 20, 60],
[100, 60, 30, 10, 50]
]
print(deikstra(f, c, 0, 3))

2.3.4К. Преобразуйте алгоритм 2.1 таким образом, чтобы при заданном начальном
состоянии он выдавал пути наименьшей стоимости для всех состояний, достижимых из
начального.
def deikstra(f, c, s0, f0):
global tree, cost, Max
Max = 600
if s0 == f0:
return 0
m = len(f)
n = len(f[1])
v = [i for i in range(n)]
cost = [Max for i in range(n)]
tree = [0 for i in range(n)]
cost[s0] = 0
for j in range(m):
t = f[j][s0]
if cost[t] > c[j][s0]:
cost[t] = c[j][s0]
tree[t] = [s0, chr(97 + j)]
v.remove(s0)
while len(v) > 0:
s = v[0]
for t in v:
if cost[t] < cost[s]:
s=t
if s == f0:
return Sol(s0, f0)
if cost[s] == Max:
return 'failure'
v.remove(s)
for j in range(m):
t = f[j][s]
if cost[t] > cost[s] + c[j][s]:
tree[t] = [s, chr(97 + j)]
cost[t] = cost[s] + c[j][s]
def Sol(s, f):
global tree, cost
L = [f]
t=f
while t != s:
L.insert(0, tree[t])
t = tree[t][0]
return cost[f], L
f=[
[1, 2, 4, 2, 3],
[4, 2, 0, 0, 3]
]
c=[
[10, 50, 10, 20, 60],
[100, 60, 30, 10, 50]
]
print(deikstra(f, c, 0, 3))
for i in range (1,5):
print(deikstra(f, c, 0, i))
i=i+1

2.3.5Т. Докажите, что алгоритм 2.1 исполняется за квадратичное время от размера


исходной таблицы, т.е. за время 𝑂(𝑛 2 ) , где 𝑛 – число состояний. Укажите оператор или
строку кода алгоритма 2.1, которая делает его нелинейным.
Сложность алгоритмов обычно оценивают по времени выполнения или по используемой памяти. В
обоих случаях сложность зависит от размеров входных данных: массив из 100 элементов будет
обработан быстрее, чем аналогичный из 1000. Важна асимптотическая сложность, т. е. сложность
при стремлении размера входных данных к бесконечности, поскольку показатель точного времени
достаточно субъективен (зависит от мощности процессора, типа данных, языка программирования и
тд).
Квадратическую сложность имеет, например, алгоритм сортировки вставками. В канонической
реализации он представляет из себя два вложенных цикла: один, чтобы проходить по всему массиву,
а второй, чтобы находить место очередному элементу в уже отсортированной части. Таким образом,
количество операций будет зависеть от размера массива как n * n, т. е. n2.
В представленном алгоритме 2.1 нелинейным его делают созданные циклы, поскольку их количество
больше 1.
2.3.6К. Запрограммируйте алгоритм 2.2 и исполните его с начальной позицией, которая была
указана на лекции (рис. 1.1 и 2.1). Можно ли дожидаться его окончания?
Окончания кода дождаться невозможно, есть вероятность, что алгоритм будет выполняться очень
долго (дольше, чем алгоритм 2.3):
def game8 (P0):
global tree, depth, z, z1, z2
if Checkpos(P0)==1:
Is0=Index(P0)
else:
return 'Bad start position'
Q=[Is0]
L = [Is0]
tree = {Is0: [0, 0]}
depth = {Is0:0}
Pos = {Is0: P0}
If0 = 12345678
Ps = [0 for i in range(9)]
Pt = [0 for i in range(9)]
while len(Q) > 0:
Is = Q[0]
for Im in Q:
Is = Im
Q.remove(Is)
if Is == If0:
return Sol(Is0, If0)
Ps = Pos[Is]
del Pos[Is]
z = Ps.index(0)
z1 = int((z - z % 3) / 3)
z2 = int(z % 3)
for x in ['Left', 'Right', 'Up', 'Down']:
Pt = Move(Ps, x)
It = Index(Pt)
if Is != It:
if It not in L:
tree[It] = [Is, x]
depth[It] = depth[Is] + 1
Pos[It] = Pt
Q.append(It)
L.append(It)
else:
return 'failure'

def Sol(Is, If):


global tree, depth
L1 = [If]
It = If
while It != Is:
L1.insert(0, tree[It][1])
L1.insert(0, tree[It][0])
It = tree[It][0]
return depth[If], L1
def Checkpos(P):
C = [0 for i in range(9)]
for i in range(9):
C[P[i]] = 1
if C.count(1) == 9:
return 1
else:
return 0
def Move(P, x):
global z, z1, z2
Q = [P[i] for i in range(9)]
if x == 'Left' and z2 > 0:
Q[z] = Q[z - 1]
Q[z - 1] = 0
elif x == 'Right' and z2 < 2:
Q[z] = Q[z + 1]
Q[z + 1] = 0
elif x == 'Up' and z1 > 0:
Q[z] = Q[z - 3]
Q[z - 3] = 0
elif x == 'Down' and z1 < 2:
Q[z] = Q[z + 3]
Q[z + 3] = 0
return [Q[i] for i in range(9)]
def Index(P):
s=0
for i in range(9):
s = s + P[i] * 10 ** (8 - i)
return int(s)
print(game8([4, 8, 0, 3, 2, 5, 6, 7, 1]))

2.3.7К. Запрограммируйте алгоритм 2.3 и исполните его с указанными эвристиками.


def game81 (P0):
global tree, depth, z, z1, z2
if Checkpos(P0)==1:
Is0=Index(P0)
else:
return 'Bad start position'
Q=[Is0]
L = [Is0]
tree = {Is0: [0, 0]}
depth = {Is0:0}
Pos = {Is0: P0}
If0 = 12345678
Ps = [0 for i in range(9)]
Pt = [0 for i in range(9)]
while len(Q) > 0:
Is = Q[0]
for Im in Q:
if Im < Is:
Is = Im
Q.remove(Is)
if Is == If0:
return Sol(Is0, If0) Ps = Pos[Is]
del Pos[Is]
z = Ps.index(0)
z1 = int((z - z % 3) / 3)
z2 = int(z % 3)
for x in ['Left', 'Right', 'Up', 'Down']:
Pt = Move(Ps, x)
It = Index(Pt)
if Is != It:
if It not in L:
tree[It] = [Is, x]
depth[It] = depth[Is] + 1
Pos[It] = Pt
Q.append(It)
L.append(It)
return 'failure'
def Sol(Is, If):
global tree, depth
L1 = [If]
It = If
while It != Is:
L1.insert(0, tree[It][1])
L1.insert(0, tree[It][0])
It = tree[It][0]
return depth[If], L1
def Checkpos(P):
C = [0 for i in range(9)]
for i in range(9):
C[P[i]] = 1
if C.count(1) == 9:
return 1
else:
return 0
def Move(P, x):
global z, z1, z2
Q = [P[i] for i in range(9)]
if x == 'Left' and z2 > 0:
Q[z] = Q[z - 1]
Q[z - 1] = 0
elif x == 'Right' and z2 < 2:
Q[z] = Q[z + 1]
Q[z + 1] = 0
elif x == 'Up' and z1 > 0:
Q[z] = Q[z - 3]
Q[z - 3] = 0
elif x == 'Down' and z1 < 2:
Q[z] = Q[z + 3]
Q[z + 3] = 0
return [Q[i] for i in range(9)]
def Index(P):
s=0
for i in range(9):
s = s + P[i] * 10 ** (8 - i)
return int(s)
print(game8([7, 2, 4, 5, 0, 6, 8, 3, 1]))
Результат:
(180, [724506831, 'up', 704526831, 'left', 74526831, 'down', 574026831, 'right', 574206831, 'up', 504276831, 'left', 54276831,
'down', 254076831, 'right', 254706831, 'up', 204756831, 'right', 240756831, 'down', 246750831, 'left', 246705831, 'down',
246735801, 'left', 246735081, 'up', 246035781, 'right', 246305781, 'right', 246350781, 'down', 246351780, 'left', 246351708, 'up',
246301758, 'right', 246310758, 'up', 240316758, 'left', 204316758, 'down', 214306758, 'left', 214036758, 'up', 14236758, 'right',
104236758, 'down', 134206758, 'down', 134256708, 'left', 134256078, 'up', 134056278, 'right', 134506278, 'right', 134560278,
'down', 134568270, 'left', 134568207, 'up', 134508267, 'left', 134058267, 'down', 134258067, 'right', 134258607, 'right',
134258670, 'up', 134250678, 'left', 134205678, 'left', 134025678, 'down', 134625078, 'right', 134625708, 'right', 134625780, 'up',
134620785, 'up', 130624785, 'left', 103624785, 'down', 123604785, 'right', 123640785, 'down', 123645780, 'left', 123645708, 'left',
123645078, 'up', 123045678, 'right', 123405678, 'right', 123450678, 'down', 123458670, 'left', 123458607, 'left', 123458067, 'up',
123058467, 'right', 123508467, 'down', 123568407, 'left', 123568047, 'up', 123068547, 'right', 123608547, 'down', 123648507,
'right', 123648570, 'up', 123640578, 'left', 123604578, 'left', 123064578, 'down', 123564078, 'right', 123564708, 'up', 123504768,
'right', 123540768, 'down', 123548760, 'left', 123548706, 'left', 123548076, 'up', 123048576, 'right', 123408576, 'down',
123478506, 'right', 123478560, 'up', 123470568, 'left', 123407568, 'down', 123467508, 'right', 123467580, 'up', 123460587, 'left',
123406587, 'left', 123046587, 'down', 123546087, 'right', 123546807, 'right', 123546870, 'up', 123540876, 'left', 123504876, 'up',
103524876, 'right', 130524876, 'down', 134520876, 'left', 134502876, 'up', 104532876, 'right', 140532876, 'down', 142530876,
'down', 142536870, 'left', 142536807, 'up', 142506837, 'up', 102546837, 'right', 120546837, 'down', 126540837, 'left', 126504837,
'down', 126534807, 'left', 126534087, 'up', 126034587, 'right', 126304587, 'right', 126340587, 'down', 126347580, 'left',
126347508, 'left', 126347058, 'up', 126047358, 'right', 126407358, 'down', 126457308, 'left', 126457038, 'up', 126057438, 'right',
126507438, 'down', 126537408, 'right', 126537480, 'up', 126530487, 'left', 126503487, 'left', 126053487, 'down', 126453087,
'right', 126453807, 'up', 126403857, 'right', 126430857, 'up', 120436857, 'left', 102436857, 'down', 132406857, 'down', 132456807,
'right', 132456870, 'up', 132450876, 'left', 132405876, 'up', 102435876, 'right', 120435876, 'down', 125430876, 'down', 125436870,
'left', 125436807, 'left', 125436087, 'up', 125036487, 'right', 125306487, 'right', 125360487, 'down', 125367480, 'left', 125367408,
'up', 125307468, 'right', 125370468, 'down', 125378460, 'left', 125378406, 'up', 125308476, 'left', 125038476, 'down', 125438076,
'right', 125438706, 'right', 125438760, 'up', 125430768, 'left', 125403768, 'down', 125463708, 'left', 125463078, 'up', 125063478,
'right', 125603478, 'right', 125630478, 'down', 125638470, 'left', 125638407, 'up', 125608437, 'left', 125068437, 'down',
125468037, 'right', 125468307, 'up', 125408367, 'left', 125048367, 'down', 125348067, 'right', 125348607, 'right', 125348670, 'up',
125340678, 'up', 120345678, 'left', 102345678, 'left', 12345678])

2.3.8К. Запрограммируйте алгоритм 2.5 и найдите все решения задачи о восьми ферзях.
Используется классический поиск с возвратом, область решений представляется в виде графа,
каждая вершина которого — это такое положение ферзя, в котором он не находится под боем, и не
бьет уже расставленных на доске ферзей, надо только собрать все «ветки» состоящей ровно из
восьми вершин. Порядок обхода графа будет выглядеть так:

def rc_queens(n_col, width, sol):


if len(sol) == width:
print (sol)
else:
for n_row in range(width):
if (safe_queen(n_row, n_col, sol)):
rc_queens(n_col+1, width, sol+[n_row])
def safe_queen(new_row, new_col, sol):
for col in range(len(sol)):
if (sol[col] == new_row or
abs(col - new_col) == abs(sol[col] - new_row)):
return 0
return 1

if __name__ == "__main__":
for n in range(8):
rc_queens(1, 8, [n])