Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Гамильтонов Цикл 
V
    Опции темы
Jiona
Дата 5.3.2006, 14:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 5.3.2006

Репутация: нет
Всего: нет



Нужно найти любой гамильнонов цикл (в данном случае он всегда существует, т.к. если n вершин, то каждая имеет N/2 дуг, выходящих из нее).
Есть хорошо работающий алгоритм (аля поиск в глубину), однако на некоторых тестах, вылетает за пределы времени (больше 7 секунд, ограничение на N<=1000).
Может быть есть какие-то усовершенстоввания?
PM MAIL   Вверх
maxim1000
Дата 5.3.2006, 14:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 33
Всего: 110



ну тогда лучше посмотреть сам алгоритм, чтобы уже можно было смотреть на возможные пути оптимизации


--------------------
qqq
PM WWW   Вверх
Jiona
Дата 5.3.2006, 22:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 5.3.2006

Репутация: нет
Всего: нет



n - число вершин, x- номер вершины с которой надо строить цикл (хотя это имеет разницу, только для вывода результата)
mas - матрица смежности, check[i] - посещена ли вершина или нет, inorder - порядок прохождения. Вообщем реализован обычный перебор.

Код

int n,k,x; 
int mas[1000][500],inorder[1000],check[1000];
bool bl=false;

void process (int per)
{
    for (int i=0;i<n/2;i++)
    {
        if (check[mas[per][i]]==0)
        {
            check[mas[per][i]]=1;
            k++;
            inorder[k]=mas[per][i];
            process(mas[per][i]);
            if (bl) return;        
        }
        if ((mas[per][i]==x-1) && (k==n-1))
        {
            bl=true;
            return;
        }
    }
    k--;
    check[per]=0;
    return;
}

PM MAIL   Вверх
maxim1000
Дата 6.3.2006, 04:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 33
Всего: 110



хм... выделим из графа 4 вершины: a,b,c,d, пусть, они все связаны
так вот если мы будем начинать наш поиск пути, например из a, то мы будем просматривать все варианты:
a,b,c,d,<тут все варианты путей для остального графа>
a,c,b,d,<тут все варианты путей для остального графа>
это я правильно понял (для этого алгоритма)?

если да, то тут есть место для оптимизации:
дело в том, что когда мы приняли к рассмотрению путь, начинающийся с a,b,c,d, мы вполне можем отсечь пути, начинающиеся с a,c,b,d, потому что они дадут точно такой же результат (не важно, положительный или отрицательный)

вот только есть проблемка: тогда нужно запоминать, какие пути мы уже просмотрели, а для этого, понадобится большой объем памяти
благодаря отсечениям количество путей не будет что-то типа n! (да к тому же и граф не полносвязный), но все равно будет немалым количеством

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

для начала введем класс CPath для хранения и сравнения путей:
CPath(i) - путь, состоящий из одной i-й вершины
path+i - путь path, к которому добавлена i-я вершина
path1==path2 - пути эквивалентны
path.Contains(i) - проверяет, содержит ли путь i-ю вершину
path.Last - номер последней вершины в пути
path.Length - длина пути

тогда функцию надо будет переписать так:
Код

array<CPath> processedpaths;
void process (CPath path)
{
    for (int i=0;i<n/2;i++)
    {
        int newnode=mas[path.Last][i];
        if (!path.Contains(newnode))
        {
            //основное изменение - отсечение
            if(!processedpaths.Find(path+newnode))//если не нашли в обработанных
                process(path+newnode);
            if (bl) return;
        }
        if (newnode==x-1) && (path.Length==n-1))
        {
            bl=true;
            return;
        }
    }
    processedpaths.Add(path);//запоминаем, что мы такой путь уже обрабатывали
}

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



--------------------
qqq
PM WWW   Вверх
Jiona
Дата 7.3.2006, 18:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 5.3.2006

Репутация: нет
Всего: нет



примерно дея понятна smile

но нашла " немного" другой алгоритм решения, даннной задачи... прошел на ура все тесты.
PM MAIL   Вверх
maxim1000
Дата 8.3.2006, 01:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Участник
Сообщений: 3334
Регистрация: 11.1.2003
Где: Киев

Репутация: 33
Всего: 110



Цитата(Jiona @ 7.3.2006, 17:40 Найти цитируемый пост)
но нашла " немного" другой алгоритм решения, даннной задачи... прошел на ура все тесты.

было бы интересно его увидеть
(перечитал... создалось ощущение какой-то скептической окраски предложения... ничего такого не подразумевалось - просто интересно smile )


--------------------
qqq
PM WWW   Вверх
Jiona
Дата 8.3.2006, 12:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 5.3.2006

Репутация: нет
Всего: нет



Алгоритм взят с кникжи Котова. Он основан на том, что из каждой вершины выходит имено N/2 дуг.
Цитата

    Задача может быть сформулирована в графовой постановке следующим образом:  найти простой цикл в графе (т.е.  без повторяющихся вершин), проходящий через все вершины графа. В общем случае не существует эффективного алгоритма решения этой задачи. Однако в данном случае задачу можно решить эффективно.
    Предположим, что  уже  построен  некоторый  простой  путь (x[1],x[2],...x[k]) Множество вершин,  вошедших в путь, будем считать пройденными, остальные не пройденные. Возможны 3 ситуации.
    1. Одна из вершин x[1],x[k] смежна одной из не пройденных еще вершин. В этом случае путь можно очевидным образом удлинить на одну вершину.
    2. Ни одна из вершин x[1],x[k] не смежна одной из не пройденных еще вершин, а вершины x[1] и x[k] смежны. В этом случае понятно,  что k>N/2,  так как вершины x[1] и x[k] смежны N/2 вершинам. Следовательно количество не пройденных вершин не больше N/2.  Следовательно любая вершина у из них смежна одной из пройденных  вершин,  например  x[i].  Но  тогда можно получить более длинный путь (у,x[i],x[i+1],...,x[k],x[1],x[2],...x[i-1]).
    3. В этом случае степеней вершин нетрудно показать, что в пути (x[1],x[2],...x[k]) существует такой индекс i,  что x[1] смежна x[i],  а  x[i-1]  смежна  x[k].  Следовательно,  рассмотрев  путь
(x[i],x[i+1],...,x[k],x[i-1],x[i-2],...x[1]) мы имеем ситуацию 2., поэтому можно получить более длинный путь.
    Применяя описанный выше способ начиная с пути длины 1,  построим простой цикл, включающий все вершины.

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Алгоритмы"

maxim1000

Форум "Алгоритмы" предназначен для обсуждения вопросов, связанных только с алгоритмами и структурами данных, без привязки к конкретному языку программирования и/или программному продукту.


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, maxim1000.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Алгоритмы | Следующая тема »


 




[ Время генерации скрипта: 0.1197 ]   [ Использовано запросов: 20 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.