Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Связный граф, его раскраска... походит на задачу о 4-х красках 
V
    Опции темы
maxdiver
Дата 17.3.2009, 23:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



KasMP
Цитата
Особенно правилен перебор "симметричных" вариантов
...
Как от них избавиться??

А чем они плохи? Нам же надо найти просто любую раскраску. Если ты имеешь в виду оптимизацию, то она вряд ли сильно спасёт (раскрасок вообще 4^N, а с учётом не-симметричности будет в 2 раза меньше), да и непонятно, как избавить перебор от них.

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

Хотя, с другой стороны, если даже в программе у нас не будет рекурсии в явном виде, то в нашем случае в памяти навряд ли что-то изменится: все равно надо помнить цвета предыдущих вершин в текущей "итерации", все равно будет создаваться что-то типа дерева рекурсии (правильно назвала?) и его глубина останется такой же. Я же правильно думаю  ?
Т.е. пытаться не использовать рекурсию в данном случае бессмысленно  ?

Ну да, если мы хотим написать рекурсивный переборный раскрасок, то нет никакого смысла пытаться написать его так, чтобы _синтаксически_ не было рекурсии. Хотя, впрочем, такая оптимизация иногда сильно помогает - избавление от рекурсии на уровне языка, замена её ручным моделированием рекурсии (со стеком). Но опять же, код усложнится и станет менее понятным, а какой прирост скорости мы получим взамен - ещё неизвестно.

Цитата
Почему  ?

[про линейное программирование] smile
Ну потому что вместо ясной задачи на графе мы получаем задачу 0-1-ЛП, которую надо как-то решать. Наверно, этому посвящены кучи теории, но чтобы написать что-то, надо всё это перелопатить smile Да и вообще, у меня есть сомнения, что по скорости этот метод вообще может быть быстрее других.

Цитата
Ну, понятно, что для проверки больше 20-30 никто не возьмет... Но для порядка пусть их будет 1024    .

Разброс нехилый smile
Для 20-30, думаю, и самый простой перебор будет укладываться. А вот для 1024 и хоть немного сложного графа - это заставит его задуматься весьма надолго smile Для 1024, наверно, уже вообще нет смысла пытаться применять точные алгоритмы раскраски...
PM MAIL WWW ICQ   Вверх
KasMP
Дата 17.3.2009, 23:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

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



Цитата(maxdiver @  17.3.2009,  23:09 Найти цитируемый пост)
А чем они плохи? Нам же надо найти просто любую раскраску.

Если раскраска хорошая, то ничем - мы ее нашли и ура smile .
А если она плохая?? Мы вернемся на уровень вверх, потом через несколько шагов попадем в "симметричную" плохую, потом снова smile ...
Цитата(maxdiver @  17.3.2009,  23:09 Найти цитируемый пост)
Ну да, если мы хотим написать рекурсивный переборный раскрасок, то нет никакого смысла пытаться написать его так, чтобы _синтаксически_ не было рекурсии. Хотя, впрочем, такая оптимизация иногда сильно помогает - избавление от рекурсии на уровне языка, замена её ручным моделированием рекурсии (со стеком). Но опять же, код усложнится и станет менее понятным, а какой прирост скорости мы получим взамен - ещё неизвестно.

Наверно, это зависит от кол-ва переменных в рекурсивной ф-ии.
В любом случае, даже при ф-ии с одной переменной i, увеличивающейся на единицу от 0 до какого-то n, мы при рекурсии одновременно будем хранить несколько экземпляров i: i=0, i=1, i=2, i=3, i=4, i=5, ... . А если делать это через циклы, то в один момент времени у нас будет одна переменная i с каким-то значением j (я только что это осознала smile ; знать-то я это и так знала, но вот сейчас почувствовала...).
i=0, i=1, i=2, i=3, i=4, i=5, ... - туповато как-то, по-моему.

Добавлено @ 23:32
Цитата(maxdiver @  17.3.2009,  23:09 Найти цитируемый пост)
А вот для 1024 и хоть немного сложного графа - это заставит его задуматься весьма надолго

Тогда пусть 1<n<=100 smile . Здесь тоже есть, что посчитать.

Это сообщение отредактировал(а) KasMP - 17.3.2009, 23:38
PM MAIL   Вверх
KasMP
Дата 21.3.2009, 23:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

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



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

Код

bool Paint (GRAPH *graph, short i)
{
    short n = graph->n;

    if (AnotherColorExists(graph,i)) {
        ++(graph->color[i]);
        for (short k=0; k<i; k++) {
            if ( Edge(graph,i,k) && SameColor(graph,i,k) ) {
                Paint (graph,i);
            }
        }
        if ( i+1 < n ) {
            graph->color[i+1] = 0;
            Paint(graph,i+1);
        }
        else
            return (true);
    }
    else {
        if ( i > 2 ) {
            graph->color[i]=0;
            Paint(graph,i-1);
        }
        else
            return (false);
    }
}

Есть ощущение, что вместо вызовов типа
Код

Paint (graph,i);
надо использовать более ... направляющие варианты:
Код

if ( Paint (graph,i); )
    return (что-то);
else
    return (противоположное);


Добавлено через 13 минут и 42 секунды
Если возникнет желание помочь, то вам может пригодиться это:
  • Используемые типы:
    Код

    struct GRAPH {
        short    n;
        bool    **adj;
        short    *color;
    };

  • Используемые при проверке функции:
    Код

    bool Edge (GRAPH *graph, short i, short j)
    { return (graph->adj[i][j] || graph->adj[j][i]); }

    bool AnotherColorExists (GRAPH *graph, short i)
    { return (graph->color[i] != num); }

    bool SameColor (GRAPH *graph, short i, short j)
    { return (graph->color[i] == graph->color[j]); }

  • Функции для графа (его матрицы смежности и раскраски) - выделение памяти, чтение из файла, удаление, вывод (на консоль), т.п.:
    Код

    void LoadNewGraph (GRAPH *graph, short t, ifstream *p_f)
    {
        graph->n = t;

        // выделение памяти для м-ы смежности из bool, запись м-ы
        (graph->adj) = new bool *[t];
        for (short i=0; i<t; i++) {
            graph->adj[i] = new bool[t];
            // чтение строки из файла в строку м-ы смежности
            for (short j=0; j<t; j++)
                *p_f >> graph->adj[i][j];
        }

        // выделение памяти для массива цветов из short, инициализация
        graph->color = new short[t];
        for (short i=0; i<t; i++)        
            graph->color[i] = 0;
    }

    void PrintMatrix (GRAPH *graph)
    {
        short n = graph->n;

        cout << "Size = " << n << "\n";    
        for (short i=0; i<n; i++) {
            for (short j=0; j<n; j++)
                cout << graph->adj[i][j] << ' ';
            cout << "\n";
        }
        cout << "\n";
    }

    void DeleteGraph (GRAPH *graph)
    {
        short n = graph->n;

        for (short i=0; i<n; i++)
            delete[] graph->adj[i];
        delete [] graph->adj;

        delete [] graph->color;
    }

    void PrintColor (GRAPH *graph)
    {
        short n = graph->n;

        for (short i=0; i<n; i++) {
            cout << "vertice " << i+1 << ": ";
            switch (graph->color[i]) {
                case 0: cout << "0 \n"; break;
                case 1: cout << "yellow \n"; break;
                case 2: cout << "blue \n"; break;
                case 3: cout << "green \n"; break;
                case 4: cout << "violet \n"; break;
            }
        }

        cout << "\n";
    }

  • Main(), которой все это предназначается:
    Код

    #include <fstream>
    #include <iostream>
    using namespace std;

    const char path1[]="C:\\in.txt";        // входной файл
    const char path2[]="C:\\out.txt";        // выходной файл
    const short num = 4;

    int main()
    {
        GRAPH graph;
        
        ifstream fin(path1); ofstream fout(path2);

        short n;
        fin >> n;    

        LoadNewGraph(&graph,n,&fin);
        PrintMatrix(&graph);
        
        
        if (Paint(&graph,0))
            PrintColor(&graph);
        else
            cout << "Impossible.";


        DeleteGraph (&graph);
        fin.close(); fout.close();

        return(0);
    }

  • Примеры исходных файлов.
    Цитата

    8
    1 0 0 0 0 0 0 0
    1 0 1 0 0 0 1 0
    0 1 0 0 0 1 0 0
    0 0 0 0 1 1 0 0
    0 0 0 1 0 1 0 0
    0 0 1 1 1 0 0 0
    0 1 0 0 0 0 0 1
    0 0 0 0 0 0 1 0

    Цитата

    4
    1 0 1 0
    1 1 1 1
    0 0 1 0
    0 1 0 0

PM MAIL   Вверх
maxdiver
Дата 22.3.2009, 00:00 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Достаточно необычно перебор написан, но конкретно по вопросу - видимо, стоит везде написать так:
Код
if ( Paint (graph,i) )
   return true;

А иначе (если вернулось false) всё будет продолжаться перебираться дальше.
PM MAIL WWW ICQ   Вверх
KasMP
Дата 22.3.2009, 00:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

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



Цитата(maxdiver @  22.3.2009,  00:00 Найти цитируемый пост)
Достаточно необычно перебор написан

В смысле плохо? Что ты имеешь в виду smile ?

Цитата(maxdiver @  22.3.2009,  00:00 Найти цитируемый пост)
видимо, стоит везде написать так:

Я думала об этом... Сейчас додумаю эту мысль до конца smile .
Спасибо smile smile  .

Добавлено через 8 минут и 44 секунды
Код

if ( i+1 < n )

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

Добавлено через 11 минут и 42 секунды
Код

if ( i > 2 )

Сюда мы попадаем, когда узнаем, что цветов для этой вершины больше нет.
Ну мы и хотим узнать, есть ли смысл подниматься в i-1 и пытаться перекрасить ее... Если i-1 - первая вершина, то нет смысла перекрашивать первую вершину в другой цвет и проверять симметричные комбинации - уходим. Если вершина где-то посередине, то можно посмотреть и поискать.
PM MAIL   Вверх
maxdiver
Дата 22.3.2009, 00:19 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Ну не то чтобы плохо, просто в некоторых местах рекурсия используется неоправданно. Ты подбираешь очередной цвет, проверяешь, не нарушает ли он правильность покраски по отношению к уже покрашенным вершинам, и если нарушает, то зачем-то вызываешь рекурсию от той же вершины. Было бы логичнее просто перебирать цвет вершины i, проверять его на корректность, и если он хороший, то вызывать рекурсию от следующей вершины, а иначе просто сразу переходить к следующей итерации цикла (цикла по цвету).
PM MAIL WWW ICQ   Вверх
KasMP
Дата 22.3.2009, 00:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

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



Цитата(KasMP @  22.3.2009,  00:07 Найти цитируемый пост)
то можно посмотреть и поискать

не забыв при этом обнулить следующие вершины

Добавлено через 6 минут и 14 секунд
Цитата(maxdiver @  22.3.2009,  00:19 Найти цитируемый пост)
и если нарушает, то зачем-то вызываешь рекурсию от той же вершины

Это делается для того, чтобы изменить цвет вершины, нарушившей правильность...
Ведь все начинается с:
Код

if (AnotherColorExists(graph,i)) {
        ++(graph->color[i]);

Т.е. мы как раз и перебираем цвет вершины i.
Что не так smile ?

Добавлено через 8 минут и 42 секунды
Еще меня добивает, что при КАЖДОМ вызове ф-ии делается
Код

short n = graph->n;

С одной стороны, логично сделать число вершин графа глобальной переменной, с другой - не хочется нарушать целостность и самодостаточность ф-ии и структуры smile.
PM MAIL   Вверх
KasMP
Дата 22.3.2009, 00:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

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



Цитата(KasMP @  21.3.2009,  23:11 Найти цитируемый пост)
В принципе мой перебор работает и дает правильные результаты

Это большая неправда.
В очевидном случае
Цитата

5
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1

он путается...

Сейчас найдем его smile .

Добавлено через 11 минут и 5 секунд
Все-таки правильнее так:
Код

if ( Paint (graph,i) )
    return (true);
else
    return (false);

smile

Добавлено через 12 минут и 58 секунд
Осталось нарисовать и раскрасить smile .
PM MAIL   Вверх
esperanto
Дата 23.3.2009, 00:15 (ссылка)    | (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


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

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



Цитата(KasMP @ 13.3.2009,  22:37)
 
Добавлено @ 22:39
Говорят, эта задача относится к классу NP-полных задач... Т.е. нет лучшего алгоритма решения, чем просто перебор smile . 

Нет.
--------------------
B.Sc ->M.Sc.->Microsoft SDE-> (Ph.D. student + Intel SDE + psyсhology B.A) - > Skype SDET
PM MAIL   Вверх
KasMP
Дата 23.3.2009, 06:31 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

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



Цитата(esperanto @  23.3.2009,  00:15 Найти цитируемый пост)
Нет. 
esperanto, это одинокое "нет" не добавляет никакой пользы. Можно подробнее smile ?

А еще у нас есть замечательная
Цитата(maxdiver @  14.3.2009,  22:10 Найти цитируемый пост)
цитата из авторитетной книги "Вычислительные машины и труднорешаемые задачи" Гэри и Джонсона:

PM MAIL   Вверх
maxdiver
Дата 23.3.2009, 13:26 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Ну, вероятно, имелось в виду, что NP-полнота не обязательно означает только переборное решение. Даже тут где-то приводилось сведЕние этой задачи к другим, например, линейное 0-1-программирование. Для них могут быть свои алгоритмы, работающие не за полиномиальное время (как, например, для линейного программирования - симплекс - за O(2^N) (или даже больше?)), но не имеющие ничего общего с перебором.

Это сообщение отредактировал(а) maxdiver - 23.3.2009, 13:29
PM MAIL WWW ICQ   Вверх
KasMP
Дата 23.3.2009, 14:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

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



Цитата(maxdiver @  23.3.2009,  13:26 Найти цитируемый пост)
Ну, вероятно, имелось в виду, что NP-полнота не обязательно означает только переборное решение. Даже тут где-то приводилось сведЕние этой задачи к другим, например, линейное 0-1-программирование. Для них могут быть свои алгоритмы, работающие не за полиномиальное время (как, например, для линейного программирования - симплекс - за O(2^N) (или даже больше?)), но не имеющие ничего общего с перебором.

Какое многообразие smile !
Эх, сколько еще предстоит узнать мне, если я не сверну с пути программиста smile...

Добавлено через 4 минуты и 33 секунды
Цитата(KasMP @  22.3.2009,  00:55 Найти цитируемый пост)
Все-таки правильнее так:
Код

if ( Paint (graph,i) )
    return (true);
else
    return (false);

smile

Кошмар какой smile smileи не поправил никто smile !
Не лучше ли просто
Код

return ( Paint (graph,i) )

PM MAIL   Вверх
KasMP
Дата 28.3.2009, 21:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

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



Ребята, а разве
Код

if ( Paint (graph,i) )
    return (true);
else
    return (false);

и
Код

return ( Paint (graph,i) );

не одно и то же smile?!

Почему-то в первом случае работает правильно, а во втором - нет...
PM MAIL   Вверх
maxdiver
Дата 28.3.2009, 23:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


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

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



Одно smile
PM MAIL WWW ICQ   Вверх
KasMP
Дата 28.3.2009, 23:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Завсегдатай
Сообщений: 586
Регистрация: 8.8.2006

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



Цитата(maxdiver @  28.3.2009,  23:05 Найти цитируемый пост)
Одно

Я так же думаю, но если заменить первое на второе, то ф-я работает неправильно smile  smile ...
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Алгоритмы"

maxim1000

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


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

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


 




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


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

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