Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Алгоритмы > np-полная (-трудная) задача или нет?


Автор: Arks 11.1.2007, 17:46
Делаю курсовик.
Задание:
Для каждой страны на географической карте известна стоимость перелёта на самолёте в другие страны, однако для каждой страны авиасообщение имеется напрямую не со всеми странами. Вено ли, что из одной страны, выбранной на карте, можно перелететь в другую выбранную страну не менее, чем N способами, не бывая в странах маршрута повторно, и заплатить при этом не более M $ ?

Преподователь сказала, что это np-полная  задача.

Одногруппник нашёл следующую np-трудную задачу, говорит, что она из книги "вычислительные машины и труднорешаемые задачи" (Сам я её не нашёл - впрочем их там много, мог проглядеть). Вот она:
Задан граф G=(V,E) с двумя выделенными вершинами s, t  V, длина L(e) каждого ребра
eE и положительные числа B и K. Существует ли в G K различных путей от s до t, веса которых не превосходят B?

Она идентична моей. В общем получается, что моя задача np-трудная и должна иметь экспоненциальную временную зависимость, однако я решил её и получил полиномиальную зависимость.

s, t - начальный и конечный пункты путешествия (вершины).
Общая схема алгоритма такая:
1. Инициализация:
    заполнил матрицу смежности w[][] стоимостью перелётов (ребра) либо значением INFINITY, если нет связи между двумя вершинами.
2. В цикле, пока "найден путь из s  в t" и "кол-во путей < N" и "стоимость < M"
    2.1  ищем кратчайший путь с помощью алгоритма Дейкстры
    2.2  если найден, то удаляем из графа все рёбра, выходящие из вершин вершин найденного пути (удаление: w[i][j]=INFINITY)
3. возвращаем результаты

Прикинул временную зависимость алгоритма:
В алгоритме Дейкстры я особо не заморачивался, поэтому его временная сложность O(n^2), где n - количество вершин
Цикл 2. в худшем случае выполняется N раз.
Итого: O(N*(n^2))

Получается обычная P-задача. Нестыковочка. 

Вот мой код:
Код

#define GM 100000

// 
// k - сколько путей искать?
// s, dest - начальная и конечная вершины
// len - массив длин кратчайших путей
// p - массив. Каждый элемент его - массив вершин одного из кратчайших путей
bool Iens(int k, int u1, int u2, int maxw, int *length, int **p)
{
    int n;        // кол-во вершин в графе
    int *w, *Pt=NULL, *a;
    int i, j, m, m1, m2, mwg, l, lt, s, wg;
    int allweight=0;    // стоимость всех перелётов
    bool c;
    VERTEX v;
    vert V;

    if(k==0)
        return false;
    // Подсчитать кол-во вершин и заполнить матрицу w
    n = 0;
    for(edgelst::iterator i1 = graph.begin(); i1!=graph.end(); i1++)
    {
        v.x = i1->x1; v.y = i1->y1; v.num = i1->num1;
        if((V.insert(v)).second)
            ++n;
        v.x = i1->x2; v.y = i1->y2; v.num = i1->num2;
        if((V.insert(v)).second)
            ++n;
    }
    //a = new int[n*n];
    w = new int[n*n];
    Pt = new int[n];
    //p = new int*[k];
    for(i=0; i<k; i++)
    {
        //p[i] = new int[n];
        for(j=0; j<n; j++)
            p[i][j] = -1;
    }
    //length = new int[k];
    for(i=0; i<n*n; i++)
        w[i] = GM;
    for(edgelst::iterator i1 = graph.begin(); i1!=graph.end(); i1++)
    {
        w[i1->num1*n+i1->num2] = w[i1->num2*n+i1->num1] = i1->cost;
    }

    for(i=0; i<k; i++)
        length[i] = -1;

    l = 1;
    m = 0;
    while(l!=-1 && m<k)
    {
        FindShortestPath(n,w,u1,u2,l,wg,Pt);
        if(l!=-1)
        {
            length[m] = l;
            allweight += wg;
            if(allweight>maxw)
                l=-1;
            else
            {
                for(i=0; i<l; i++)
                    p[m][i] = Pt[i];
                // Удалить обработанные vertexes and edges из графа
                for(i=0; i<l-1; i++)
                    w[Pt[i]*n+Pt[i+1]] = w[Pt[i+1]*n+Pt[i]] = GM;
                for(i=1; i<l-1; i++)
                    for(j=0; j<n; j++)
                        w[Pt[i]*n+Pt[j]] = w[Pt[j]*n+Pt[i]] = GM;
            }
        }
        ++m;
    }
    if(l==-1)
        return false;

    delete[] Pt;
    delete[] w;

    return true;
}
// Find the shortest path in graph (Dejkstra's algorith)
// s = source; dest = destination
bool FindShortestPath(int n, int *w, int s, int dest, int& len, int& weight, int *Path)
{
    int length;
    int i, j, k, min, d1, t;
    int *d, *p, *m;
    vert V;    // Additional var.

    //Path = new int[n];
    for(i=0; i<n; i++)
        Path[i] = -1;
    d = new int[n];
    p = new int[n];
    m = new int[n];

    length = 0;
    i = 0;
    do{
        d[i] =GM;
        p[i] = 0;
        m[i] = 0;
        ++i;
    }while(i<n);
    d[s] = 0;
    m[s] = 1;
    t = s;
    while(!length)
    {
        i = 0;
        do{
            if(w[t*n+i]<GM)
            {
                d1 = d[t] + w[t*n+i];
                if(d[i]>d1)
                {
                    d[i] = d1;
                    p[i] = t;
                }
            }
            ++i;
        }while(i<n);
        min = GM;
        i = 0;
        k = -1;
        do{
            if(m[i]==0)
            {
                if(d[i]<min)
                {
                    min = d[i];
                    k = i;
                }
            }
            ++i;
        }while(i<n);
        if(k==-1)
        {
            length = -1;
        }
        else
        {
            m[k] = i;
            t = k;
            if(t==dest)
            {
                length = 1;
            }
        }
    }
    if(length==1)
    {
        Path[0] = dest;
        ++length;
        j = dest;
        do{
            Path[length-1] = p[j];
            j = p[j];
            ++length;
        }while(j!=s);
        i = 0;
        j = n-1;
        k = !(length%2) ? length/2 : length/2 + 1;
        do{
            t = Path[i];
            Path[i] = Path[j];
            Path[j] = t;
            ++i; --j;
        }while(i<=k);
        --length;
        while(Path[0]==-1)
        {
            for(i=0; i<n-1; i++)
                Path[i] = Path[i+1];
        }
    }
    weight = d[dest];
    len = length;

    delete[] d;
    delete[] p;
    delete[] m;

    return length>=0;
}

Автор: Mayk 11.1.2007, 17:59
Цитата(Arks @  11.1.2007,  21:46 Найти цитируемый пост)
2.2  если найден, то удаляем из графа все рёбра одной из вершин которой является одна из вершин найденного пути (удаление: w[i][j]=INFINITY)

Что значит "одной из вершин"? 
Рассмотрим
Код

 s
 |
 B
/ \
C D
\ /
 t

из s в t есть два пути(s,b,c,t & s,b,d,t). Однако, если удалить вершину B, то они не будут найдены.

Автор: Arks 11.1.2007, 18:56
Нормально. Мы можем проходить через 1 вершину только 1 раз (за искл. s & t), так что все нормально.

Автор: esperant0 11.1.2007, 21:59
"моя задача np-трудная и должна иметь экспоненциальную временную зависимость"

Конечно же не должна.

Автор: SoWa 12.1.2007, 05:17
Откройте любую книжку по графам и отыщите там задачу комивояжера. Почти такая как у вас.... К нижке же все про сложность и хороший алгоритм найдете.

Автор: ~FoX~ 12.1.2007, 08:41
Поиск по разделу по славам задача коммивояжера и орграфы....Тема поднималась не раз....Конкретно твоя задача по нахождению пути в ориентированном графе. 
Цитата(Arks @  11.1.2007,  18:46 Найти цитируемый пост)
Получается обычная P-задача. Нестыковочка. 

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

Автор: esperant0 12.1.2007, 09:34
Цитата(~FoX~ @ 12.1.2007,  08:41)
  
Не получается, задача двухкриториальная - стоимость, направление (ориентация графа), по определению не может быть пи задачей.

Сколько лет занимаюсь теорией вычислимости - а о таком загадочном определении не слышал.

Можете ссылочку, или док-во привести? smile 

Автор: Arks 12.1.2007, 09:42
esperant0, 
Цитата
Конечно же не должна. 

Почему?


SoWa, 
~FoX~, 
У меня неориентированный граф, и задача коммивояжёра никак к моему случаю не относится. Точно вам говорю.

Существует алгоритм Йена, но он ищет минимальные отклонения, а не полностью новый путь. Да и в любом случае у него тоже полиномиальное время работы. Мою же программу преподователь не приняла, так как сказала, что моя задача np-трудная (см. сравнение с np-трудной задачей в первом посте) и соответсвенно её решение не может иметь полиномиальную временную зависимость. А у меня так.

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

Цитата(~FoX~)
по определению не может быть пи задачей

Почему? В "вычислительные машины и труднорешаемые задачи" задача есть - указано, что она p-задача:
кратчайший путь между 
двумя вершинами 
УСЛОВИЕ. Заданы: граф 
G = (V, Е), длины l(e)eZ+ для 
всех е s Е, выделенные вершины 
a, ie7 и положительное целое 
число В. 
ВОПРОС. Существует ли в G 
простой путь из а в Ъ, имеющий 
длину не более В? 

Автор: esperant0 12.1.2007, 10:00
Цитата(Arks @ 12.1.2007,  09:42)
esperant0, 
Цитата
Конечно же не должна. 

Почему?

 

А почему должна -то? Нет такой теоремы что должна и не было. Разве что ВЫ ее доказали?

Автор: ~FoX~ 12.1.2007, 11:46
Arks, Блин, я извиняюсь, это я вопрос не до конца дочитал, с утра не проснулся еще.  smile 

Автор: Arks 12.1.2007, 14:38
esperant0, ну ладно, уломал. Допустимо ещё псевдополиномиальное время.  smile 
Вот, нашёл я свою задачу в книге, сам. Там есть примечание:
Комментарий. Принадлежность этой задачи классу NP не уста- 
установлена. Аналогичная задача о кратчайших циклах также NP- 
трудна. Обе задачи остаются NP-трудными и тогда, когда 
1(е)= 1 для всех ееЕ. То же самое верно для аналогичных 
задач в ориентированных графах. Однако все варианты этой 
задачи могут быть решены за псевдополиномиальное время 
(т. е. время, ограниченное полиномом от |V|, К и log В) и, 
следовательно, за полиномиальное время при любом фиксиро- 
фиксированном значении числа К- Соответствующие перечислительные 
задачи КР-полны. 

Итак, у меня не полиномиальное время, а псевдополиномиальное. Только вот объясните мне, чем полиноми.. отличается от псевдо..? Псевдо, потому что коэффициент K может быть любым? Потому что не постоянен? Просто, даже если K будет == n (кол-во вершин в графе), то максимум получим n^3 -а это никак не экспоненциальное время (2^d, 3^d, ... ) - всё-таки задачи включаются в np-полные за их сложность.
Что такого особенно в псевдополиноми.. так сказать?

Автор: esperant0 12.1.2007, 15:10
Не вдаваясь в подробности псевдополиномиальное это как эспоненциальное время.

Автор: Arks 12.1.2007, 16:32
Понятно. Вот, что накопал:
Псевдополиномиальное означает, что с увеличением параметров время растёт экспоненциально.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)