Алгоритм Дейкстры Java — неправильное расстояние

#java #algorithm #dijkstra

#java #алгоритм #dijkstra

Вопрос:

Я пытаюсь закодировать алгоритм Дейкстры, начиная с любой вершины, мне нужно показать расстояние и напечатать путь к узлам. Он работает для вершин 2,4 и 5, но для 1 и 3 он запутывается. Вероятно, это что-то глупо маленькое, но я этого не вижу.

 public static void main(String[] args)
{
    int INF = Integer.MAX_VALUE;
    int verticies = 5;
    int W[][] = {{INF,7,4,6,1},
    {0,INF,0,0,0},
    {0,2,INF,4,0},
    {0,0,0,INF,0},
    {0,0,0,1,INF}};

    int startNode = 1;
    dijkstra(W,verticies,startNode-1);

}

public static void dijkstra(int G[][],int n,int startnode)
{
    int INF = Integer.MAX_VALUE, nINF = Integer.MIN_VALUE;
    //int cost[MAX][MAX],distance[MAX],pred[MAX];
    //int visited[MAX],count,mindistance,nextnode,i,j;
    int cost[][] = new int[n][n];
    int distance[] = new int[n];
    int pred[] = new int[n];
    boolean visited[] = new boolean[n];
    int count=0, mindistance=0, nextnode=0,i,j;

    //pred[] stores the predecessor of each node
    //count gives the number of nodes seen so far
    //create the cost matrix
    for(i=0;i<n;i  )
        for(j=0;j<n;j  )
            if(G[i][j]==0)
                cost[i][j]=INF;
            else
                cost[i][j]=G[i][j];

    //initialize pred[],distance[] and visited[]
    for(i=0;i<n;i  )
    {
        distance[i]=cost[startnode][i];
        pred[i]=startnode;
        visited[i]=false;
    }

    distance[startnode]=0;
    visited[startnode]=true;
    count=1;

    while(count<n-1)
    {
        mindistance=INF;

        //nextnode gives the node at minimum distance
        for(i=0;i<n;i  )
            if(distance[i]<mindistanceamp;amp;!visited[i])
            {
                mindistance=distance[i];
                nextnode=i;
            }

        //check if a better path exists through nextnode
        visited[nextnode]=true;
        for(i=0;i<n;i  )
            if(!visited[i])
                if(mindistance cost[nextnode][i]<distance[i])
                {
                    distance[i]=mindistance cost[nextnode][i];
                    pred[i]=nextnode;
                }
        count  ;
    }

    //print the path and distance of each node
    for(i=0;i<n;i  )
        if(i!=startnode)
        {
            if(distance[i] == INF || distance[i] < 0){
                System.out.print("nNo edge exists between node " (startnode 1) " and node " (i 1));
            } else {
                System.out.format("nDistance of node %d = %d", (i   1), distance[i]);
                System.out.format("nPath = %d", (i   1));

                j = i;
                do {
                    j = pred[j];
                    System.out.format("<-%d", (j   1));
                } while (j != startnode);
            }
        }
}
  

Комментарии:

1. Подсказка: вы поместили туда довольно много кода. То есть трудный для чтения код. Не удивляйтесь, если ответов не слишком много. Вместо этого я рекомендую А) научиться использовать отладчик Б) прочитать о «Чистом коде». Я бы начал с того, что не помещал все это в один метод. Вместо этого: разделите вещи на как можно больше маленьких методов.

2. Плюс: я предлагаю всегда всегда ставить { вокруг блоков }. Тааак легко сделать что-то неправильно, если этого не делать!

3. @Felicia Я не знаю, в чем проблема, но одна вещь выглядит странно: с помощью строки «visited [nextnode] = true;» вы помечаете узел (полученный из набора подключенных узлов) с минимальным весом как посещенный. Я думаю, что в соответствии с алгоритмом узел помечается как посещенный, когда посещаются все его соседние узлы.

4. @Felicia Я думаю, что этот класс, который я написал github.com/rajatIIT/graph_algo_practice/commit / … может вам помочь . Как сказал GhostCat, более четкий код хорош.

5. Я опубликовал все как есть, потому что в прошлый раз пользователь накричал на меня за то, что я не опубликовал достаточно кода… Извините, я все еще пытаюсь найти золотую середину.

Ответ №1:

Я не знаю точно, как, но вы каким-то образом попадаете INF в свои вычисления. Мое подозрение касается строки distance[i]=mindistance cost[nextnode][i]; , но это может быть не единственный виновник, я не проверял. Когда mindistance равно 1 (или больше) и стоимость равна Integer.MAX_VALUE , вы получаете арифметическое переполнение, и результат становится отрицательным. Дальнейшее поведение я не предсказывал, но оно не такое, как ожидалось.

Когда в двух местах, которые вы определяете INF , я меняю значение на 1 000 000, я получаю следующий вывод из вашей программы:

 Distance of node 2 = 6
Path = 2<-3<-1
Distance of node 3 = 4
Path = 3<-1
Distance of node 4 = 2
Path = 4<-5<-1
Distance of node 5 = 1
Path = 5<-1
  

Я считаю, что это правильно.

Как я узнал? Я вставил это утверждение в середину вашего внешнего цикла while:

         System.out.println("count "   count   " nextnode "   nextnode   " mindistance "   mindistance);
  

Когда он напечатал большое отрицательное число, я начал подозревать арифметическое переполнение. Пока вы не научитесь использовать отладчик, System.out.println() это ваш друг для отладки.

Комментарии:

1. Вы рекомендуете отладчик?

2. Отладчик незаменим для профессионального программиста. У него нет какой-либо крутой кривой обучения, поэтому вы можете начать в удобном для вас темпе.

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

4. Хорошие IDE, такие как IntelliJ IDEA и Eclipse, имеют хорошие встроенные отладчики. Если вам интересно, вы можете скачать Eclipse бесплатно и начать его пробовать.