Содержание предисловие 2 веб-страницы 3 введение 6 1архитектура ЭВМ 17




НазваниеСодержание предисловие 2 веб-страницы 3 введение 6 1архитектура ЭВМ 17
страница76/78
Дата конвертации11.12.2012
Размер5.58 Mb.
ТипРеферат
1   ...   70   71   72   73   74   75   76   77   78

Сложность задач


В разделе 11.4 мы исследовали проблемы в терминах разрешимости. В этом разделе нас будет интересовать сложность задач (complexity of problem), то есть вопрос, существует ли практическое решение разрешимых задач. Мы узнаем, что некоторые теоретически разрешимые проблемы настолько сложны, что их невозможно решить с практической точки зрения.

Измерение сложности задачи


Мы начнем с возвращения к изучению эффективности алгоритмов, начатому в разделе 4.6. Там мы применяли ©-представление (большая тета-представле-ние) для классификации алгоритмов в зависимости от времени их выполнения. Мы узнали, что алгоритм сортировки вставкой принадлежит классу 0(и2), алгоритм последовательного поиска — классу Э(и), а алгоритм бинарного поиска — классу @(\gn). Теперь эта классификационная система поможет нам вычислять сложность задач. Наша цель — разработать классификационную систему, при помощи которой можно будет определить, какие проблемы являются более сложными, чем другие, и, в итоге, какие проблемы настолько сложны, что их решение невозможно в практическом смысле.

Причина того, что мы базируем наше текущее исследование на знании эффективности алгоритмов, состоит в том, что мы хотим измерить сложность проблем в терминах сложности их решений. Мы считаем задачу простой, если ее решение просто; сложная задача — это задача, для которой нет простого решения. Обратите внимание: тот факт, что решение задачи является сложным, не означает, что сама проблема сложна. Действительно, у задачи может быть несколько решений, и одно из них просто обязано быть сложным. Следовательно, чтобы утверждать, что проблема сложна, необходимо показать, что ни одно из ее решений не является простым.

Предметом вычислительной техники являются задачи, которые умеют решать машины. Решения этих задач формулируются в виде алгоритмов. Таким образом, сложность проблемы определяется свойствами алгоритмов, решающих ее. Точнее, сложность простейшего алгоритма для решения задачи считается сложностью этой задачи.

Но как же измерить сложность алгоритма? К сожалению, термин «сложность» можно интерпретировать по-разному. Например, можно рассматривать количество принятых решений и ветвлений алгоритма. С этой точки зрения сложный алгоритм должен иметь разветвленный, переплетенный набор указаний. Эта интерпретация может быть удобна разработчику программного обеспечения, которого интересуют вопросы разработки и представления алгоритма, но не вопрос сложности с точки зрения машины. При выборе очередной инструкции для выполнения машина на самом деле не принимает решения, просто выполняет машинный цикл снова и снова, каждый раз выполняя команду, на которую указывает счетчик команд. Следовательно, машина выполняет набор сложных инструкций как простой последовательный список команд. То есть в этом случае измеряются, скорее, трудности, возникающие при создании алгоритмов, а не сложность самих алгоритмов.

Интерпретацию, которая более точно отражает сложность алгоритма, можно получить, рассматривая алгоритмы с точки зрения машины. В этом контексте мы измеряем сложность алгоритма в терминах времени, необходимого для его выполнения, которое пропорционально количеству требуемых действий. Обратите внимание, что это количество не совпадает с числом команд в написанной программе. Цикл, тело которого состоит из одного оператора печати, но который должен выполниться 100 раз, во время выполнения эквивалентен 100 операторам печати. Следовательно, такая процедура считается более сложной, чем список из 50 отдельно написанных операторов печати, хотя этот список выглядит длиннее в тексте программы. Дело в том, что значение сложности в конечном итоге определяется временем, которое требуется машине для выполнения алгоритма, а не размером программы, представляющей решение.

Таким образом, мы считаем задачу сложной, если для ее решения требуется много времени. Это определение сложности называется временной сложностью (time complexity). Мы уже неявно познакомились с концепцией временной сложности во время изучения эффективности алгоритмов в главе 4 (раздел 4.6). Действительно, изучение эффективности алгоритмов выливается в изучение их временной сложности — это всего лишь две стороны одной медали. То есть «более эффективный» алгоритм равен «менее сложному». Так, в терминах временной сложности, алгоритм последовательного поиска (эффективность которого равна ©(и)) является более сложным решением задачи поиска в списке, чем алгоритм бинарного поиска (чья эффективность равна 0(lg n)).

Применим наши знания сложности алгоритмов в поиске способов определения сложности задач. Мы считаем, что (временная) сложность задачи равна Э(У(гс)), где /(и) — это некоторая математическая функция от п, если существует алгоритм решения этой задачи, временная сложность которого равна Q(f(n)), и не существует других алгоритмов решения с меньшей временной сложностью. То есть (временная) сложность задачи определяется как (временная) сложность ее наилучшего решения. К сожалению, поиск лучшего решения задачи и доказательство, что оно действительно лучшее, — это зачастую сложная проблема сама по себе. В таких ситуациях для обозначения того, что нам известно о сложности задачи, применяется О-представление (вариант в-представления). Точнее, если f(ri) — это математическая зависимость от п и если задачу можно решить алгоритмом класса @(/(п)), то мы говорим, что это задача класса О(/(п)). То есть говоря, что задача принадлежит О(/(и)), мы имеем в виду, что для нее есть решение со сложностью 0(/(и)), но, возможно, существуют и более хорошие решения.

Пространственная сложность


Альтернативой измерению сложности в терминах времени является изменение пространственных требований — такое измерение известно под названием пространственной сложности (space complexity). Пространственная сложность задачи определяется количеством машинной памяти, необходимой для решения задачи. В этой главе мы узнали, что временная сложность сортировки списка из п записей равна О(л 1д п). Пространственная сложность той же задачи не превышает О(л + 1) = О(л). Действительно, для сортировки списка из п записей методом вставки необходимо пространство для хранения самого списка и еще одной временной записи. Таким образом, если нам потребуется сортировка все более длинных списков, мы увидим, что время, требуемое для выполнения каждой задачи, будет увеличиваться быстрее, чем расходуемое пространство. Это достаточно распространенный феномен. Так как использование пространства требует времени, пространственная сложность задачи никогда не будет увеличиваться быстрее, чем ее временная сложность.

Часто между временной и пространственной сложностью ищутся какие-либо компромиссы. В некоторых приложениях удобнее выполнять определенные вычисления заранее и хранить результаты в таблице, из которой при необходимости их легко восстановить. Такая техника табличного поиска сокращает время, необходимое конечной системе, за счет дополнительного пространства, которое занимает таблица. С другой стороны, сжатие данных зачастую применяется для сокращения требований к пространству, но при этом необходимо дополни-; тельное время для сжатия и восстановления данных.

Наши исследования процессов поиска и сортировки приводят к выводу, что задача поиска в списке длиной п (когда все, что мы знаем о списке — что он был предварительно упорядочен) принадлежит O(lg n), так как эту задачу может решить бинарный поиск. Кроме того, исследователи показали, что проблема поиска в действительности принадлежит 0(lg n), то есть бинарный поиск является оптимальным решением задачи. С другой стороны, мы знаем, что задача сортировки списка длиной п (когда мы ничего не знаем об исходном распределении значений в списке) принадлежит О(п2), потому что алгоритм сортировки вставкой может решить эту задачу. Однако, как показали исследования, задача сортировки принадлежит Q(n lg n), то есть алгоритм сортировки вставкой — это не оптимальное решение (в смысле временной сложности).

Примером лучшего решения является алгоритм сортировки слиянием. Он состоит в объединении небольших отсортированных частей списка для получения более крупных отсортированных фрагментов, которые объединяются в еще более длинные отсортированные отрезки списка. Каждый процесс слияния выполняется при помощи алгоритма слияния (листинг 8.1), который мы рассмотрели при обсуждении последовательных файлов. Для удобства мы еще раз расмот-рим его (листинг 11.3), в этот раз на примере слияния двух упорядоченных списков. Полный (рекурсивный) алгоритм сортировки слиянием представлен в виде процедуры MergeSort (листинг 11.4). Когда эта процедура получает список для сортировки, сначала она проверяет, содержится ли в списке более одной записи. Если нет, то задача процедуры выполнена. Если записей больше одной, процедура делит список на две части, которые отправляет для сортировки другим копиям процедуры MergeSort, а затем объединяет отсортированные части для получения конечного отсортированного варианта списка.

Листинг 11.3. Процедура MergeLists для объединения двух упорядоченных списков

procedure MergeLists (InputListA. InputListB, OutputList)

if (оба входных списка пусты) then (Остановиться, список OutputList пуст)

if (InputListA пуст)

then (Объявляем его пустым)

else (Объявляет его первую запись его текучей записью) if- (InputListB пуст)

then (Объявляем его пустым)

else (Объявляет его первую запись его текущей записью) while (ни один из входных списков не пуст) do

(Поместить "меньшую" текущую запись в OutputList;

if (эта текущая запись - последняя в соответствующем входном списке) then (Объявить этот входной список пустым) else (Объявить следующую запись этого входного списка текущей записью этого списка)

) Начиная с текущей записи непустого входного списка, скопировать оставшиеся записи

в OutputList.

Листинг 11.4. Алгоритм сортировки слиянием, реализованный в процедуре MergeSort

procedure MergeSort (List) if (В списке List более одной записи) then

(Применить процедуру MergeSort для сортировки первой половины списка List: Применить процедуру MergeSort для сортировки второй половины списка List:

Применить процедуру MergeLists для объединения первой и второй половины списка List

и получения отсортированной версии List )

Чтобы проанализировать сложность этого алгоритма, сначала найдем количество сравнений записей списка, необходимое для слияния списка длиной г со списком длиной s. Процесс слияния заключается в последовательном сравнении записей из одного списка с записями другого и помещении меньшего значения в выходной список. Таким образом, каждый раз, когда производится сравнение, количество оставшихся записей уменьшается на одну. Так как алгоритм начинает работать на г + s записей, мы делаем вывод, что процесс слияния двух списков потребует не более г + s сравнений.

Теперь рассмотрим алгоритм сортировки слиянием полностью. Он решает задачу сортировки списка длиной п так, что исходная задача сортировки разделяется на две меньших, когда сортируются списки длиной приблизительно "/2. Эти две задачи, в свою очередь, делятся еще раз, и мы получаем четыре задачи сортировки списков длиной приблизительно "Д. Этот процесс деления можно представить при помощи дерева на рис. 11.5, где каждый узел соответствует одной задаче в рекурсивном процессе, а ветви, исходящие из каждого узла, — это задачи меньшего размера, полученные из родительской задачи. Следовательно, мы можем найти общее количество сравнений, производимых в процессе сортировки, сложив количество сравнений, найденное в узлах дерева.



Сначала определим количество сравнений на каждом уровне дерева. Задача каждого узла на определенном уровне дерева — сортировать уникальный сегмент исходного списка. Это делается при помощи процесса слияния и, следовательно, требует сравнений не больше, чем есть записей в сегменте списка, что мы уже показали. Поэтому на каждом уровне дерева количество сравнений будет не больше общего количества записей в сегментах списка, а так как сегменты на данном уровне дерева являются непересекающимися частями исходного списка, конечное число сравнений будет не больше длины исходного списка. Следовательно, на каждом уровне дерева потребуется не более п сравнений. (Конечно, на нижнем уровне выполняется сортировка списков длиной 1 или менее, и сравнения не требуются вовсе.)

Теперь подсчитаем количество уровней в дереве. Для этого обратите внимание, что процесс деления задач на меньшие продолжается, пока не будут получены списки длиной менее двух. Поэтому количество уровней в дереве определяется количеством возможных операций деления на два, начиная со значения п до получения результатов, не превышающих единицу, то есть lg п. Точнее, в дереве может быть не более fig n\ уровней, требующих сравнений, где обозначение fig п\ — это округление lg п до ближайшего целого, большего lg п.

Наконец, общее количество сравнений, которые выполняет алгоритм сортировки слиянием при сортировке списка длиной п, получается умножением количества сравнений на каждом уровне на количество уровней, на которых требуются сравнения. Мы делаем вывод, что оно не превышает п Fig n\ Так как график функции пFig n\имеет ту же форму, что и график п lg n, то алгоритм сортировки слиянием принадлежит О(« lg n). Учитывая тот факт, что сложность задачи сортировки равна Q(n lg n), можно утверждать, что алгоритм сортировки слиянием является оптимальным решением задачи сортировки.

Полиномиальные и не полиномиальные задачи


Предположим, что /(и) и g{ri) — математические выражения. Утверждение, что g(n) ограничена f(ji), означает, что, вычисляя эти выражения на растущих значениях и, значения/(и) в итоге становятся больше значений g(n) и превышают g(n) на всех дальнейших значениях п. Другими словами, то, что g(n) ограничена/(и), означает, что график/(и) находится выше графика g(n) для «больших» значений п. Например, выражение lg п ограничено п (рис. 11.6, а), а п lg n ограничено п2 (рис. 11.6, б).



Мы называем задачу полиномиальной (polynomial problem), если она принадлежит О(/(и)), где f{n) — это полином (многочлен), или это выражение ограничено полиномом. Набор всех полиномиальных задач обозначается Р. Обратите внимание, что наши предыдущие исследования показали, что задачи поиска в списке и сортировки списка принадлежат Р. Утверждение о том, что задача является полиномиальной, говорит о времени, необходимом для решения задачи. Мы часто говорим, что задача из Р может быть решена в полиномиальное время или что у этой задачи решение с полиномиальным временем.

Поиск задач, принадлежащих Р, является одной из главных проблем вычислительной техники, так как он тесно связан с вопросами о том, существует ли для задач практическое решение. Действительно, задачи, не входящие в Р, характеризуются очень большим временем выполнения, даже для небольших входов. Например, представим себе задачу, решение которой выполняется за 2" шагов. Экспоненциальное выражение 2" не ограничено ни одним полиномом. Действительно, если f{n) — полином, то с увеличением значения п мы обнаружим, что значения 2" всегда будут больше значений /(я). Это означает, что алгоритм сложности Э(2") в общем случае будет менее эффективным, и для его выполнения потребуется больше времени, чем для алгоритма сложности Э(/(и)). Говорят, что для алгоритма, сложность которого определяется экспоненциальным выражением, требуется экспоненциальное время.

Рассмотрим пример. Представьте проблему перечисления всех возможных подгрупп, которые можно сформировать из группы, состоящей из п человек. Так как таких подгрупп может быть 2" — 1 (мы считаем подгруппой всю группу, но не допускаем пустых подгрупп), любой алгоритм для решения этой задачи должен состоять минимум из 2" - 1 шагов, и его сложность будет, по крайней мере, равна этому значению. Но выражение 2" - 1, будучи экспоненциальным, не ограничено ни одним полиномом. Следовательно, любое решение этой задачи по мере увеличения размера группы, из которой выбираются подгруппы, требует огромного времени выполнения.

В противоположность задаче о подгруппах, сложность которой велика только из-за размера выхода, существуют задачи, чья сложность может быть высокой, даже если конечный выход — это просто ответ «да» или «нет». Например, способность отвечать на вопросы о правдивости утверждений, требующих сложения действительных чисел. Мы легко можем сказать, что ответом на вопрос «Правда ли, что существует действительное число, которое при сложении с самим собой дает значение 6?» будет «да», а на вопрос «Правда ли, что существует ненулевое действительное число, которое при сложении с самим собой дает 0?» — «нет». Однако если подобные вопросы становятся все более сложными, наша способность отвечать на них ослабевает. Если мы столкнемся с большим количеством подобных вопросов, то, вероятно, захотим воспользоваться компьютерной программой для ответа на них. К сожалению, поиск ответов на эти вопросы требует экспоненциального времени, поэтому в итоге компьютеры не могут сохранять регулярность при ответе на все более сложные вопросы.

То, что теоретически разрешаемые проблемы, не принадлежащие Р, имеют огромную временную сложность, заставляет нас признать, что их невозможно решить с практической точки зрения. Ученые, занимающиеся вычислительной техникой, называют такие задачи трудно разрешимыми. В свою очередь, задачи, для которых существуют практические решения, содержатся в Р. Поэтому понимание границ класса Р стало важной областью исследований вычислительной техники.

NP-задачи


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

Традиционное решение этой задачи — последовательно рассматривать возможные пути, сравнивая длину каждого с пределом проездных денег, пока не будет найден подходящий путь или все возможности не будут исчерпаны. Однако этот подход требует неполиномиального времени решения. С увеличением количества городов количество путей, которые потребуется проверить, увеличивается быстрее любого полинома. Следовательно, решение задачи коммивояжера для большого количества городов таким способом невозможно.

Мы делаем вывод, что для решения задачи в разумное время требуется более быстрый алгоритм. Наш аппетит подогревается подозрением, что, если подходящий путь существует и мы выберем его первым, решение будет найдено очень быстро. В частности, следующий список команд можно быстро выполнить и получить возможное решение задачи:

Взять один из возможных путей и подсчитать общую длину пути. if (длина пути не превышает допустимой)

then (объявить об успехе)

else (ничего не объявлять)

Но этот набор команд не является алгоритмом в техническом смысле. Его первая инструкция двусмысленна — она не указывает, какой из путей выбрать и из чего исходить при принятии решения. Она полагается на фантазию механизма выполнения программы, предоставляя выбор решения ему. Мы говорим, что такие инструкции недетерминированы, и называем «алгоритм», содержащий подобные указания, недетерминированным, алгоритмом (nondeterministic algorithm).

Обратите внимание, что с увеличением количества городов время, необходимо для выполнения этого недетерминированного алгоритма, увеличивается достаточно медленно. Процесс выбора пути заключается в простом выводе списка городов, на что требуется время, пропорциональное количеству городов. Кроме того, время, необходимое для вычисления полной длины выбранного пути, также пропорционально количеству городов, а время сравнения пути с предельно допустимым не зависит от числа городов. Следовательно, время выполнения недетерминированного алгоритма ограничено полиномом. Поэтому задачу о коммивояжере можно решить при помощи недетерминированного алгоритма в полиномиальное время.

Конечно, наше недетерминированное решение не идеально. Оно основано на случайном выборе. Однако его существования достаточно для предположения, что, возможно, есть и детерминированное решение задачи коммивояжера, которое выполняется в полиномиальное время. Правда это или нет — пока что открытый вопрос. В действительности, задача коммивояжера — лишь одна из задач, для которых известны недетерминированные решения, выполняемые в полиномиальное время, и для которых детерминированного решения с полиномиальным временем пока что не найдено. Дразнящая эффективность недетерминированных решений этих задач заставляет надеяться, что однажды будут найдены и эффективные детерминированные решения, но большинство убеждены, что эти проблемы все же слишком сложны и выходят за рамки возможностей эффективных детерминированных алгоритмов.

Детерминированность против недетерминированности


Во многих случаях лишь тонкая грань отделяет детерминированные алгоритмы от недетерминированных. Но различие между ними достаточно очевидно и существенно. Детерминированный алгоритм не надеется на творческие способности механизма, выполняющего алгоритм, тогда как для недетерминированного «алгоритма» они могут быть достаточно важны. Например, сравните команды

Дойдите до следующего перекрестка и поверните направо или налево. и

Дойдите до следующего перекрестка и поверните направо или налево в зависимости от того, что скажет вам человек, стоящий на углу.

В обоих случаях действие, которое выполнит инструктируемый, не определено до начала выполнения команды. Однако первая команда требует от человека последовать направлению, выбранному им самостоятельно, то есть это недетерминированная инструкция. Вторая команда не предъявляет подобных требований к человеку — он получает инструкции на каждом шаге. Если первую команду выполнят несколько человек, то некоторые из них повернут направо, а другие — налево. Если несколько человек выполнят вторую команду и получат одинаковую информацию, то все повернут в одном направлении. В этом и заключается важное различие между детерминированными и недетерминированными «алгоритмами». Если детерминированный алгоритм выполнять несколько раз с одинаковыми входными данными, то выполненные действия всегда будут одинаковыми. В то же время недетерминированный алгоритм в одних и тех же условиях может привести к получению различных результатов.

Задача, которая может быть решена за полиномиальное время при помощи недетерминированного алгоритма, называется недетерминированной полиномиальной задачей (nondeterministic polynomial problem), или NP-задачей. Класс NP-задач обозначается NP. Обратите внимание, что все задачи из Р также принадлежат NP, так как к любому (детерминированному) алгоритму можно добавить недетерминированную комайду, не влияющую на работу алгоритма.

Ответа на вопрос, все ли NP-задачи находятся в Р, пока что нет, что демонстрирует нам задача коммивояжера. Возможно, это самая известная нерешенная задача вычислительной техники на сегодняшний день. Ее решение могло бы иметь значительные последствия. Например, в следующем разделе мы узнаем, что существуют системы шифрования, целостность которых зависит от огромного количества времени, необходимого для решения задач, схожих с задачей коммивояжера. Если окажется, что эффективные решения подобных задач существуют, такие системы шифрования будут подвергнуты риску.

Усилия по поиску ответа на вопрос, совпадает ли класс NP с классом Р, привели к обнаружению в классе NP нового класса задач, известного как NP-полные задачи (NP-complete problem). У этих проблем есть общее свойство, которое заключается в том, что решение с полиномиальным временем любой из них обеспечило бы решение с полиномиальным временем для всех остальных NP-задач. То есть, если найдется (детерминированный) алгоритм для решения одной из NP-полных задач в полиномиальное время, то этот алгоритм можно было бы расширить для решения всех остальных задач из NP в полиномиальное время. Следовательно, было бы доказано, что класс NP совпадает с классом Р. Задача коммивояжера является одной из NP-полных задач.

Подведем итог. Мы обнаружили, что задачи могут быть разрешимыми (имеющими алгоритмическое решение) и неразрешимыми (для которых нет алгоритмического решения), что показано на рис. 11.7. Более того, в классе разрешимых задач есть два подкласса. Первый — это набор полиномиальных задач, то есть задач, имеющих практическое решение. Второй представляет собой не полиномиальные задачи, практическое решение для которых может быть найдено только для относительно небольших и тщательно отобранных входов. И в заключение, существуют загадочные NP-задачи, не поддающиеся точной классификации.


1   ...   70   71   72   73   74   75   76   77   78

Похожие:

Содержание предисловие 2 веб-страницы 3 введение 6 1архитектура ЭВМ 17 iconОсновы работы с Sharepoint в какое место веб-страницы разрешается вставить новую веб-часть (в браузере)?
В какое представление веб-страницы будут вноситься изменения, если выбрать команду Настроить эту страницу?
Содержание предисловие 2 веб-страницы 3 введение 6 1архитектура ЭВМ 17 iconВведение в физику и технологию элементной базы ЭВМ и компьютеров
Введение   8
Содержание предисловие 2 веб-страницы 3 введение 6 1архитектура ЭВМ 17 iconСодержание
Содержание размещают после титульного листа отчёта (как правило, на стр. 2). Слово «Содержание» рас­полагают посередине страницы...
Содержание предисловие 2 веб-страницы 3 введение 6 1архитектура ЭВМ 17 iconСоздание веб-страницы в простом текстовом редакторе
Давайте создадим  веб-страницу. Для этого нужно напечатать ее исходный код в простом текстовом редакторе  блокнот
Содержание предисловие 2 веб-страницы 3 введение 6 1архитектура ЭВМ 17 iconЗагрузка uploading теория
После того как набор html страниц веб-сайта создан. Все они связаны между собой с помощью ссылок. Страницы наполнены контентом. Таким...
Содержание предисловие 2 веб-страницы 3 введение 6 1архитектура ЭВМ 17 iconЛитература 153 Алфавитный указатель 155 Предисловие редактора русского издания Глубокоуважаемые коллеги! Содержа­ние этой книги значительно шире и глуб­же, нежели заявлено в ее названии. Я бы назвала ее «Лечение и реставрация молочных зубов»
Предисловие редактора русского издания 6 Введение 9 Предисловие 11 Благодарности 13
Содержание предисловие 2 веб-страницы 3 введение 6 1архитектура ЭВМ 17 icon        Информатика  Системы счисления и  арифметические основы эвм  
Введение   
Содержание предисловие 2 веб-страницы 3 введение 6 1архитектура ЭВМ 17 iconЯндекс - поисковая машина, способная по вашему запросу найти в русскоязычной части интернета наиболее подходящие веб-страницы, новости, картинки, статьи
Яндекс — поисковая машина, способная по вашему запросу найти в русскоязычной части интернета наиболее подходящие веб-страницы, новости,...
Содержание предисловие 2 веб-страницы 3 введение 6 1архитектура ЭВМ 17 iconВзаимодействие веб-сайтов по культуре с пользователем. 
Предисловие к русскому изданию   4 
Содержание предисловие 2 веб-страницы 3 введение 6 1архитектура ЭВМ 17 iconВзаимодействие веб-сайтов по культуре с пользователем. 
Предисловие к русскому изданию   4 
Разместите кнопку на своём сайте:
kak.znate.ru


База данных защищена авторским правом ©kak.znate.ru 2012
обратиться к администрации
KakZnate
Главная страница