Ответы на вопросы:
Лаб. Раб. №5:
Какова структура машины Тьюринга?
На рис.1 представлена структурная схема машины Тьюринга, где
обозначены буквами:
B – внешняя память машины, которую можно интерпретировать,
как неограниченную в обе стороны ленту, разделенную на элементарные ячейки;
Q – внутренняя память машины, определяющая состояния, в которых находится машина в любой момент времени;
G – считывающая (записывающая) головка;
Z – логический блок машины. Этот блок формирует символ, который будет записан на ленту, а также управляет переходами машины из
одного состояния в другое;
P – устройство, управляющее головкой.
Что такое внутренняя и внешняя память машины Тьюринга?
B – внешняя память машины, которую можно интерпретировать, как неограниченную в обе стороны ленту, разделенную на элементарные ячейки;
Q – внутренняя память машины, определяющая состояния, в которых находится машина в любой момент времени;
В чем заключается особенность построения функциональных таблиц?
Исходными данными являются двоичные символы 0 и 1. Работа
алгоритма определяется четырьмя состояниями: q0, q1, q2, qk.
Тройка символов q10R, записанная на пересечении строки q0 и
столбца 0, означает: если машина находится в состоянии q0 и с ленты
будет считан символ 0, то машина перейдет в состояние q1, на ленту будет записан символ 0, и головка сдвинется на один символ вправо.
Какова связь функциональной таблицы с функциональной диаграммой?
В чем смысл умножения машин Тьюринга?
Система команд (таблица или диаграмма) машины Т является результатом объединения системы команд машин T1 и T2. Нетрудно видеть, что машина Т = T1·T2 работает так, как если бы после завершения работы машины T1 начала работать машина T2. Очевидно, что произведение машины Тьюринга некоммутативно, т.е. T1· T2 ≠ T2 T1.
Что такое итерация машин Тьюринга?
Итерация машин Тьюринга заключается в отождествлении r-го состояния останова машин Тьюринга с начальным состоянием.
Код на C++ лр2:
#include <iostream>
#include <vector>
#include <queue>
#include <utility>
#include <cstring>
#include <climits>
using namespace std;
// `N` - общее количество узлов на Graphе или городов на карте
#define N 5
// Сторожевое значение для представления `INFINITY`
#define INF INT_MAX
// Узлы State Space Tree
struct Node
{
// сохраняет ребра дерева в пространстве состояний
// помощь в отслеживании пути при нахождении ответа
vector<pair<int, int>> path;
// сохраняет уменьшенную матрицу
int reducedMatrix[N][N];
// сохраняет нижнюю границу
int cost;
// сохраняет текущий номер города
int vertex;
// сохраняет общее количество посещенных городов
int level;
};
// Функция выделения нового узла `(i, j)` соответствует посещению города `j`
// из города `i`
Node* newNode(int parentMatrix[N][N], vector<pair<int, int>> const &path,
int level, int i, int j)
{
Node* node = new Node;
// сохраняет ребра-предки дерева в пространстве состояний
node->path = path;
// пропустить корневой узел
if (level != 0)
{
// добавляем к пути текущее ребро
node->path.push_back(make_pair(i, j));
}
// копируем данные из родительского узла в текущий узел
memcpy(node->reducedMatrix, parentMatrix,
sizeof node->reducedMatrix);
// Изменяем все записи строки `i` и столбца `j` на `INFINITY`
// пропустить корневой узел
for (int k = 0; level != 0 && k < N; k++)
{
// устанавливаем исходящие ребра для города `i` в `INFINITY`
node->reducedMatrix[i][k] = INF;
// устанавливаем входящие ребра в город `j` на `INFINITY`
node->reducedMatrix[k][j] = INF;
}
// Установите `(j, 0)` в `INFINITY`
// здесь начальный узел равен 0
node->reducedMatrix[j][0] = INF;
// установить количество посещенных городов на данный момент
node->level = level;
// присваиваем номер текущего города
node->vertex = j;
// return node
return node;
}
// Функция для сокращения каждой строки так, чтобы в каждой строке был хотя бы один ноль
int rowReduction(int reducedMatrix[N][N], int row[N])
{
// инициализируем массив строк значением `INFINITY`
fill_n(row, N, INF);
// `row[i]` содержит минимум в строке `i`
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if (reducedMatrix[i][j] < row[i]) {
row[i] = reducedMatrix[i][j];
}
}
}
// уменьшаем минимальное значение каждого элемента в каждой строке
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if (reducedMatrix[i][j] != INF && row[i] != INF) {
reducedMatrix[i][j] -= row[i];
}
}
}
}
// Функция для уменьшения каждого столбца так, чтобы там был хотя бы один ноль
// в каждом столбце
int columnReduction(int reducedMatrix[N][N], int col[N])
{
// инициализируем все элементы массива `col` значением `INFINITY`
fill_n(col, N, INF);
// `col[j]` содержит минимум в col `j`
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if (reducedMatrix[i][j] < col[j]) {
col[j] = reducedMatrix[i][j];
}
}
}
// уменьшаем минимальное значение каждого элемента в каждом столбце
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N; j++)
{
if (reducedMatrix[i][j] != INF && col[j] != INF) {
reducedMatrix[i][j] -= col[j];
}
}
}
}
// Функция для получения нижней границы пути, начинающегося с текущего минимального узла
int calculateCost(int reducedMatrix[N][N])
{
// инициализировать стоимость до 0
int cost = 0;
// Сокращение строк
int row[N];
rowReduction(reducedMatrix, row);
// Сокращение столбца
int col[N];
columnReduction(reducedMatrix, col);
// общая ожидаемая стоимость равна сумме всех сокращений
for (int i = 0; i < N; i++)
{
cost += (row[i] != INT_MAX) ? row[i] : 0,
cost += (col[i] != INT_MAX) ? col[i] : 0;
}
return cost;
}
// Функция для печати списка посещенных городов по наименьшей стоимости
void printPath(vector<pair<int, int>> const &list)
{
for (int i = 0; i < list.size(); i++) {
cout << list[i].first + 1 << " —> " << list[i].second + 1 << endl;
}
}
// Объект сравнения, который будет использоваться для упорядочивания кучи
struct comp
{
bool operator()(const Node* lhs, const Node* rhs) const {
return lhs->cost > rhs->cost;
}
};
// Функция для решения задачи о коммивояжёре с использованием метода ветвей и границ
int solve(int costMatrix[N][N])
{
// Создаем приоритетную очередь для хранения активных узлов дерева поиска
priority_queue<Node*, vector<Node*>, comp> pq;
vector<pair<int, int>> v;
// создаем корневой узел и вычисляем его стоимость.
// TSP начинается с первого города, т.е. узла 0
Node* root = newNode(costMatrix, v, 0, -1, 0);
// получаем нижнюю границу пути, начинающегося в узле 0
root->cost = calculateCost(root->reducedMatrix);
// Добавляем корень в список живых узлов
pq.push(root);
// Находит живой узел с наименьшей стоимостью, добавляет его потомков в список
// живые узлы и, наконец, удаляем их из списка
while (!pq.empty())
{
// Находим активный узел с наименьшей оценочной стоимостью
Node* min = pq.top();
// Найденный узел удаляется из списка живых узлов
pq.pop();
// `i` хранит текущий номер города
int i = min->vertex;
// если все города посещены
if (min->level == N - 1)
{
// вернуться в начальный город
min->path.push_back(make_pair(i, 0));
// вывести список посещенных городов
printPath(min->path);
// возвращаем оптимальную стоимость
return min->cost;
}
// делаем для каждого дочернего элемента min
// `(i, j)` образует ребро в пространственном дереве
for (int j = 0; j < N; j++)
{
if (min->reducedMatrix[i][j] != INF)
{
// создаем дочерний узел и вычисляем его стоимость
Node* child = newNode(min->reducedMatrix, min->path,
min->level + 1, i, j);
/* Стоимость дочернего элемента =
стоимость родительской ноды +
стоимость ребра(i, j) +
нижняя граница пути, начинающегося в узле j
*/
child->cost = min->cost + min->reducedMatrix[i][j]
+ calculateCost(child->reducedMatrix);
// Добавляем дочерний элемент в список активных узлов
pq.push(child);
}
}
// свободный узел, так как мы уже сохранили ребра `(i, j)` в векторе.
// Так что нет необходимости в родительском узле при печати решения.
delete min;
}
}
int main()
{
// матрица затрат для задачи коммивояжера.
/*
int costMatrix[N][N] =
{
{INF, 5, INF, 6, 5, 4},
{5, INF, 2, 4, 3, INF},
{INF, 2, INF, 1, INF, INF},
{6, 4, 1, INF, 7, INF},
{5, 3, INF, 7, INF, 3},
{4, INF, INF, INF, 3, INF}
};
*/
// стоимость 34
int costMatrix[N][N] =
{
{ INF, 7, 12, 25, 10 },
{ 10, INF, 9, 5, 11 },
{ 13, 8, INF, 6, 4 },
{ 6, 11, 15, INF, 15 },
{ 5, 9, 12, 17, INF }
};
/* С удалением ребра
int costMatrix[N][N] =
{
{ INF, 7, 12, 25, 10 },
{ 10, INF, 9, INF, 11 },
{ 13, 8, INF, 6, 4 },
{ 6, 11, 15, INF, 15 },
{ 5, 9, 12, 17, INF }
};
*/
/*
// стоимость 16
int costMatrix[N][N] =
{
{INF, 3, 1, 5, 8},
{3, INF, 6, 7, 9},
{1, 6, INF, 4, 2},
{5, 7, 4, INF, 3},
{8, 9, 2, 3, INF}
};
*/
/*
// стоимость 8
int costMatrix[N][N] =
{
{INF, 2, 1, INF},
{2, INF, 4, 3},
{1, 4, INF, 2},
{INF, 3, 2, INF}
};
*/
/*
// стоимость 12
int costMatrix[N][N] =
{
{INF, 5, 4, 3},
{3, INF, 8, 2},
{5, 3, INF, 9},
{6, 4, 3, INF}
};
*/
cout << "\n\nTotal cost is\n" << solve(costMatrix);
return 0;
}
Код на C++ лр5:
#include <iostream>
#include <string>
#include <stdexcept>
using namespace std;
string convert(string unary_input) {
int result = 0;
if (unary_input.empty()) {
unary_input = "0";
} else {
for (size_t i = 0; i < unary_input.length(); ++i) {
if (unary_input[i] != '|') {
throw invalid_argument("Введена не унарная запись");
}
result += 1;
if (result > 9) {
return string(1, unary_input[result - 2]);
}
unary_input[i] = '0' + result;
}
}
return string(1, unary_input[result - 1]);
}
int main() {
string unary_input = "||||";
string result = convert(unary_input);
cout << unary_input << ": " << result << endl;
return 0;
}
