Форум Академгородка, Новосибирск > Традиционно-предсессионное
Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Традиционно-предсессионное
Форум Академгородка, Новосибирск > Образование > Школьный форум > Форум ВКИ
fenster
Господа,

Приближается очередная сессия, и я снова (как обычно) готов отвечать на ваши вопросы как по моему любимому курсу методов программирования, так и по другим "околопрограммерским" или математическим курсам (в меру своей испорченностикомпетенции). Вот ссылка на аналогичную тему прошлого семестра: http://forum.academ.org/index.php?showtopic=201872

Не бойтесь, спрашивайте, если что-то непонятно. Экзамены обычно показывают, что непонятно бывает многое, к сожалению.
reflex603
Вот вопрос по организационной части наверно. Вот по информационным технологиям как примерно будет оцениваться сайт который мы пишем будет оцениваться идея и дальнейшее его продвижение или всё таки больше програмная часть.?
rolleyes.gif
fenster
На этот вопрос я, к сожалению, ответить не могу -- не в курсе, "не мой" предмет. Если тут есть преподаватели ИТ, они вам ответят.
Марийка
Цитата(reflex603 @ 12.12.2007, 0:44) *
Вот вопрос по организационной части наверно. Вот по информационным технологиям как примерно будет оцениваться сайт который мы пишем будет оцениваться идея и дальнейшее его продвижение или всё таки больше програмная часть.?
rolleyes.gif

Если базовый проект по "ИТ", то и то, и другое.
Если курс "ИТ", который ведёт уважаемый Мерзляков М.М., то лучше всё-таки у него лично спросить.
reflex603
Не Мерзляков М.М. а Мерзляков М.А. supdup.gif
Вот ещё сегодня писали контрольную которую вы придумали по методам. Там 2-ое задание 1-ый пункт типо: обойти графф с помощью остовного леса. Не могли бы вы изложить алгоритм и если не трудно с примером.
Буду очень признателен! rolleyes.gif
fenster
Скорее всё-таки "построить остовный лес для данного ориентированного графа методом обхода в глубину, начиная от вершины 1" smile.gif

Рассмотрим обычный обход графа в глубину (рекурсивно) с пометкой вершин в массиве int visited[N]:

Код
void dfs(int curr)
{
    visited[curr] = 1;
    for (перебираем все вершины i, достижимые из curr)
        if (!visited[i])
            dfs(i);
}


Нажмите для просмотра прикрепленного файла

Скажем, на графе на первом рисунке функция dfs(1), начав обход в вершине 1 и пометив её как пройденную, перейдёт в вершину 6, пометит её и завершится (больше ни до какой вершины дойти не получится). Чтобы в конечном итоге перебрать все вершины графа, можно написать примерно такой цикл:

Код
for (i = 0; i < N; i++)
    if (!visited[i])
        dfs(i);


Тогда следующим шагом после завершения dfs(1) будет найдена следующая непосещённая вершина: 2. Из неё мы попадём в вершину 3. Пойти в 6 из 3 мы не можем, т.к. 6 уже посещена, так что этот обход здесь тоже завершается. Следующим шагом будет посещена вершина 4 (из неё мы никуда не можем пойти, всё посещено) и в самом конце -- вершина 5. На втором рисунке изображён полученный остовный лес (набор остовных деревьев).

Нажмите для просмотра прикрепленного файла
Люциф
Дык вот, про "традицинно-предсессионное" как раз... У кого есть вопросы к экзаменам?!*^.^* На NT2/books воопще фиг чё найдёшь!:(
fenster
Выложил вопросы на сайте: вот они. Заодно пробежался по ним глазами и выяснил, что несколько тем забыл разобрать на лекциях; на субботней лекции все эти пробелы будут закрыты.
Люциф
Ну ничего ужасного в вопросах я не заметил. Штук пять мы не разбирали, это правда, но обо всём остальном вы нам рассказывали.smile.gif
Paradoxx [HomeNet]
Цитата(fenster @ 13.12.2007, 12:39) *
...
Тогда следующим шагом после завершения dfs(1) будет найдена следующая непосещённая вершина: 2. Из неё мы попадём в вершину 3. Пойти в 6 из 3 мы не можем, т.к. 6 уже посещена, так что этот обход здесь тоже завершается. Следующим шагом будет посещена вершина 4 (из неё мы никуда не можем пойти, всё посещено) и в самом конце -- вершина 5. На втором рисунке изображён полученный остовный лес (набор остовных деревьев).
Нажмите для просмотра прикрепленного файла

Ну это понятно. Вот сделали вы обход в глубину, обошли все 6 вершин, а как остовный лес-то построился?) Я немного не понял :-(
в visited записались же вершины 1,2,3,4,5 и 6 ?

И осветите, пожалуйста, 34 35 и 36 вопросы. Лекция у нас была полное _ .=\
fenster
В остовный лес попадают рёбра, по которым мы проходим. То есть, если идёт рекурсивный вызов dfs(i), то ребро (curr, i) попадает в остовный лес.
fenster
34. Эйлеровы циклы.

Сначала определения. Эйлеров путь -- путь в графе, который проходит по каждому ребру графа ровно один раз. Эйлеров цикл -- замкнутый эйлеров путь.

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

Существует несколько алгоритмов построения эйлерова цикла (если известно, что он существует).

Алгоритм Флёри. Мост -- ребро, при удалении которого из графа в нём увеличивается количество компонент связности.

Код
0. Выбрать произвольную вершину curr.
1. Если в графе есть ребро (curr, i), не являющееся мостом, выполнить:
    1а. вывести его в ответ,
    1б. удалить его из графа,
    1в. присвоить curr = i и снова перейти к шагу 1.
2. Если в графе есть ребро (curr, i), являющееся мостом, выполнить:
    2а. вывести его в ответ,
    2б. удалить его из графа,
    2в. присвоить curr = i и перейти к шагу 1.
3. Если из вершины curr нет ребёр, завершить выполнение алгоритма.


Алгоритм со стеком. Используется стек, в который кладутся рёбра графа.

Код
0. Выбрать произвольную вершину curr.
1. Если в графе есть ребро (curr, i), выполнить:
    1а. удалить его из графа,
    1б. присвоить curr = i,
    1в. push(curr, i) и перейти к шагу 1.
2. Если в графе нет рёбер из вершины curr, выполнить:
    2а. если стек пуст, выход.
    2б. выполнить pop(), если (x, y) -- полученное из стека ребро, то присвоить curr = x.
    2в. вывести ребро (x, y).
    2г. перейти к шагу 1.

fenster
35. Гамильтоновы циклы.

Гамильтонов цикл -- цикл, который проходит по каждой вершине графа ровно один раз.

Гамильтонов цикл в графе ищется при помощи обхода в глубину с возвратом, т.е. по сути полным перебором всех путей.

Тут ещё можно сказать, что задача поиска гамильтонова цикла наименьшей стоимости во взвешенном (помеченном) графе называется задачей коммивояжёра.
fenster
36. Динамическое программирование. Кратко можно прочитать здесь.
Akullina
Расскажите пожалуйста транзитивное замыкание, а то я что то в нем запуталась

fenster
Транзитивное замыкание графа G = (V, E) -- это граф G' = (V, E') такой, что (i, j) принадлежит E' тогда и только тогда, когда в G есть путь из i в j. Если по-русски, то если в графе можно каким-либо образом пройти из одной вершины в другую, то в замыкании будет ребро между этими двумя вершинами.

Пример: для ориентированного графа, состоящего из вершин 1, 2, 3 и рёбер (3, 1) и (1, 2), транзитивным замыканием будет граф из тех же вершин 1, 2, 3 и рёбер (3, 1), (1, 2) и (3, 2) (последнее ребро -- "новое", появилось, т.к. из 3 в 2 можно пройти в исходном графе).

Строгий алгоритм построения транзитивного замыкания по сути ничем не отличается от алгоритма Флойда:

Код
for (i пробегает по всем вершинам) -- зафиксировали "центральную" вершину
    for (j, k перебирают все пары вершин)
        if (есть ребро из j в i и есть ребро из i в k)
            добавить ребро из j в k

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

На тесте пользоваться этим алгоритмом не нужно, для такого маленького графа, как там, замыкание делается просто "глазами": перебираем пары вершин и смотрим, можно ли пройти из одной в другую. Если можно, рисуем (дорисовываем) ребро.
Paradoxx [HomeNet]
Большое спасибо.
Задачи сложные будут? Я лошара, на 16 всего написал %( А переписать на 18 сказали не дадут, чтобы от задач освободили.
fenster
Да нет, не очень сложные. Правда, бывают иногда громоздкие задачи.
MaxArt
Вот у меня появилось пару вопросов по второй части экзаменационных вопросов:

1)Сразу стало непонятно, что нужно рассказывать в вопросах №1 и №2.

2)В лекциях не нашёл определение иерархических списков. В связи с этим возник вопрос о реализации топологической сортировки с помощью этих списков.

3)Незнакома мне структура данных под названием «куча».

p.s. на какую часть экзам. вопросов (№1 или №2) экзаменаторы будут больше обращать внимание?

Заранее спасибо!

fenster
1. Статическое и динамическое распределение памяти. Способы доступа к данным (прямой, последовательный, индексный, косвенный). Работа с динамической памятью в Си.

Если "на пальцах", то здесь нужно сказать о том, что под определённые в программе переменные (как глобальные, так и локальные -- так называемые автоматические) память выделяется компилятором автоматически. Время жизни переменной, определённой после открывающей фигурной скобки, начинающей некоторый блок -- до конца этого блока. Если это нас не устраивает, необходимо выделять и освобождать память вручную при помощи функций malloc/realloc и затем освобождать её при помощи функции free. Память, выделенная таким образом, будет жить и после выхода из блока, в котором произошло выделение.

По поводу способов доступа к данным: здесь имеется в виду примерно следующее. Прямой доступ -- обращение к ячейке памяти, когда мы чётко знаем её адрес, например, когда мы обращаемся к обычной переменной. Косвенный доступ -- доступ через указатель, т.е. разыменование указателя: в переменной-указателе находится адрес нужного нам значения в памяти. Индексный доступ -- обращение к элементу массива a[i], когда адрес нужного значения вычисляется как сдвиг на i элементов от начала массива. Последовательный доступ -- доступ к элементам списка, когда чтобы дойти до 20го элемента, мы должны перебрать 19 предыдущих.

2. Динамические типы данных в языках программирования: организация, описание, доступ. Указатели.

Здесь нужно рассказать в общем про структуру и создание одно- и двусвязных списков, иерархических списков, деревьев, описать, как производится вставка и удаление элементов, перебор элементов.
fenster
Собственно, что касается иерархических списков -- это такой список, в каждом элементе которого хранится голова списка. Например, так:
Код
struct item2 {
    int data;
    struct item2 *next;
};
struct item1 {
    struct item2 *head;
    struct item1 *next;
};
struct item1 *head;

При помощи такой или подобной структуры можно представить граф (список смежности), а там уже и топологическую сортировку на нём сделать.

По поводу кучи: куча (heap) -- структура данных, с которой вы неявно встречались в топологической сортировке. Определяется она как структура данных со следующими операциями:
1. Вставить элемент;
2. Извлечь максимальный элемент;
3. Проверить на пустоту;
причём первая и вторая операция выполняются за время O(log N), где N -- число элементов в куче. При реализации кучи данные хранятся в массиве A длины N таким образом, что для каждого i одновременно выполняются два условия:
1) если 2 * i + 1 < N, то A[i] >= A[2 * i + 1];
2) если 2 * i + 2 < N, то A[i] >= A[2 * i + 2].
При добавлении элемента он вставляется в конец и выполняется "просеивание наоборот", максимальный элемент забирается с верхушки кучи, меняется на последний и выполняется просеивание. См. пирамидальную сортировку.
Paradoxx [HomeNet]
Спасибо большое за помощь!
А можно просто сказать, что куча - это и есть динамическая память? Или это неправильно?

И что такое задачи с коммивояжером и т.п. ?smile.gif Я, честно говоря, первый раз такое вижу smile.gif
26. Классические переборные задачи. Коммивояжер, рюкзак, устойчивые бракосочетания. Способы их решения (обзорно).
27. Классические переборные задачи. Задача коммивояжера.
fenster
Не путайте две разные кучи. Куча как часть памяти, доступной программе для выделения блоков (malloc, realloc, calloc) и освобождения (free) -- это одно. Куча как структура данных (стек, очередь, дек, куча) -- это другое (то, что я описал выше).

Теперь по классическим задачам. Задача коммивояжёра -- задача поиска гамильтонова цикла наименьшей длины во взвешенном неориенированном графе. Традиционно формулируется так: есть набор городов и указаны стоимости перелёта между городами. Коммивояжёру необходимо объехать все города ровно по одному разу и вернуться, затратив при этом минимально возможное количество денег. Точное решение задачи коммивояжёра можно найти только перебором с откатом.

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

Задача об устойчивых браках -- задача о поиске максимального паросочетания в двудольном графе. Граф называется двудольным, если его можно правильно раскрасить в два цвета. Другими словами, если множество вершин делится на две части (доли) так, что любое ребро соединяет вершину из одной доли с вершиной из другой доли. Паросочетанием в двудольном графе называется множество рёбер, не имеющих общих вершин.* Так вот, в задаче требуется найти максимальное по количеству рёбер паросочетание в данном двудольном графе. Это можно понимать так (задача об устойчивых браках, или задача об игре "Любовь с первого взгляда", если угодно): есть несколько мужчин и несколько женщин, у каждого есть некоторые предпочтения по поводу противоположного пола (один или несколько человек). Какое максимальное количество пар можно выделить, уважая предпочтения каждого участника? Задача легко решается перебором, плюс есть более простой алгоритм (сложности N^3), который вам на лекциях не рассказывали (и на экзамене спрашивать его не будут).

---------------------------------------------------------
* Вообще говоря, понятие паросочетания можно аналогичным образом ввести для произвольного графа.
Paradoxx [HomeNet]
Т.е. в 26-м билете достаточно сказать то, что написали Вы,
а в 27-м нужно первую задачу еще и решить этим самым "перебором с откатом"?smile.gif Хы.
fenster
Не вполне: я тут не полные ответы на экзамене пишу, а только указываю направление, в котором надо развиваться мысли smile.gif Хотя меня самого такие ответы бы удовлетворили (как многие знают, я вообще с небольшим интересом отношусь к ответу по билету). А что касается перебора с откатом -- это же обычный dfs (см. выше), в котором в конце добавлена одна строчка visited[curr] = 0. Тем самым перебор всех достижимых вершин сразу превращается в перебор всех возможных путей (ничего сложного также нет в сохранении текущего пути), а из перебора всех путей сделать поиск гамильтонова цикла наименьшей длины тоже ничего сложного. Как-то примерно так:
Код
int A[N][N]; // матрица смежности
int start; // начальная вершина
int bestpath[N + 1], bestlength = -1;
void salesman(int curr, int currlen, int count, int currpath[N]) // решение задачи коммивояжёра полным перебором
{ // curr -- номер текущей вершины, currlen -- длина текущего пути, count -- кол-во вершин в текущем пути, currpath -- текущий путь
    int i;
    if (count == N && A[curr][start] && (bestlength == -1 || currlen + A[curr][start] < bestlength))
    { // если все вершины пройдены, из текущей есть ребро до начальной и длина лучше всех, что были раньше
        for (i = 0; i < count; i++)
            bestpath[i] = currpath[i];
        bestpath[count] = start;
        bestlength = currlen;
        return;
    }
    if (bestlengh != -1 && currlength > bestlength) // если текущая длина уже стала хуже лучшей -- дальше искать нет смысла
        return;
    visited[curr] = 1;
    currpath[count] = curr;
    for (i = 0; i < N; i++) // стандартный цикл обхода в глубину
        if (!visited[i] && A[curr][i])
            salesman(i, currlen + A[curr][i], count + 1, currpath);
    visited[curr] = 0;
}

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

Но по умолчанию должно быть достаточно уметь описать алгоритм, а код писать уже по требованию экзаменатора.
Paradoxx [HomeNet]
Хм, нам Куртов сегодня на консультации сказал ,что задач про коммивояжеров и всякие браки нету в программе обучения, а значит и не будет на экзамене О_о
fenster
Может, и не будет. Знать-то всё равно надо. Я исходил из предположения, что билеты не менялись с прошлого года (если они менялись, то как-то мимо меня smile.gif )
Trampam
Как реализовать с помощью иерархических списков топологическую сортировку? часть два, вопрос 6.
fenster
А в чём проблема? Граф храним как список смежности, в каждой вершине для удобства можно также хранить количество входящих в неё рёбер.
Paradoxx [HomeNet]
Цитата(fenster @ 08.01.2008, 20:48) *
А в чём проблема? Граф храним как список смежности, в каждой вершине для удобства можно также хранить количество входящих в неё рёбер.

В этом билете надо про вагончики рассказать? Типо такого?

Нажмите для просмотра прикрепленного файла

Это, наверное, еще и в 8м билете можно рассказать, там где "Динамическая структура со списками дуг."
fenster
Да-да-да-да. Да там многие билеты так или иначе пересекаются.
Paradoxx [HomeNet]
ну тогда гуд лак нам завтра :cry:
Trampam
все было не так уж и страшно smile.gif
MoLь
Мде, меня прогнали почти по всему курсу... Успела даже испугаться, что плакала моя пятерка smile.gif Хорошо хоть, двусвязных компонент не спросили, я так и не поняла алгоритм их поиска О_о

fenster
Советую-таки разобраться по теории -- там на самом деле весьма красивый алгоритм. Радует, что из года в год несколько один-два человека в группе его таки понимают smile.gif
fenster
Ну и хочется отдельно поздравить "своих" с получением именно тех оценок, которые вы должны были получить smile.gif
MoLь
Ага, я, кстати. целый час до экзамена искала человека, который его понимал бы... не получилось smile.gif
Кстати, по теории с твоего сайта я разобраться тоже не смогла. Хотя честно пыталась несколько раз smile.gif

А насчет оценок... кажется, Сашка на тебя теперь очень злая ;)
fenster
Я только могу повторить про получение тех оценок, которые вы должны были получить. Я специально обе ведомости (А1 и А2) посмотрел и был приятно удивлён адекватностью оценок. Так что обижаться недовольным студентам надо в первую очередь на себя: мне кажется, оценки замечательно отражают работу в семестре и знания. Я же тоже разговаривал с экзаменаторами и знаю, кто как отвечал smile.gif

Что касается точек сочленения, Сергей Нестеров, думаю, может тебе всё объяснить при желании.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Русская версия IP.Board © 2001-2024 IPS, Inc.