2015-04-20 1 views
2

EDIT: [решено]Оптимизация для Дейкстры требуется (уникальный алгоритм)

ИМЕЮТ ВЗГЛЯД НА МОЕ ОТВЕТ НА ЭТОЙ СТРАНИЦЕ


Alright так в моем стремлении реализовать O (N.lgN) Решение Дийкстры в JAVA, я понял, что в первую очередь было трудно создать кортежи для смежных вершин и весов для каждой вершины. Это может easiy быть сделано в C++ с использованием:

pair<int adv_vertex,int weight> 

Если вы понятия не имеете, о чем я говорю о том, посмотрите на это решение: http://qr.ae/LoESY

Теперь, несмотря на все трудности, я нашел контейнер похож на «пара <>» в JAVA. В качестве примера (1,1), объявленное как:

Map.Entry<Integer, Integer> pair=new AbstractMap.SimpleEntry<Integer,Integer>(1,1); 

Читайте подробности здесь: https://stackoverflow.com/a/11253710/4258892

Теперь, мне удалось в реализации алгоритма Дейкстры с использованием этого структура данных. Я использовал TreeSet с пользовательским компаратором. Это в значительной степени работает как PriorityQueue, который извлекает вершины с наименьшим весом в первую очередь. Этот вопрос можно рассматривать как расширенный вариант:

Having trouble Implementing a Custom Comparator for a TreeSet (Dijkstra's)

После Everthing было сделано, я попробовал свои силы на эту проблему:

http://www.spoj.com/problems/EZDIJKST/

Он очищает выборочные testcases, но я получаю предел TLE() TIme Exceeded) при подаче. Так много для реализации Dijkstra, как никто никогда не имел.

Вот код, который получил TLE: http://ideone.com/wAQfBu

И вот моя фактическая реализация Дейкстра с объяснением. Тот, который я представил SPOJ, просто без комментариев и выходных запросов. Это может занять некоторое время, чтобы вы могли опустить голову. Я пробовал комментировать, где и когда это возможно.

import java.io.*; 
import java.util.*; 

    /** 
    * Created by Shreyans on 3/25/2015 at 7:26 PM using IntelliJ IDEA (Fast IO Template) 
    */ 

    class DIJKSTA_TRY 
    { 
     public static void main(String[] args) throws Exception 
     { 
      InputReader in = new InputReader(System.in); 
      //Initializing Graph 

      //AbstractMap.SimpleEntry<Integer,Integer> is similar to pair<int a,int b> in C++ 

      List<ArrayList<AbstractMap.SimpleEntry<Integer,Integer>>>gr=new ArrayList<ArrayList<AbstractMap.SimpleEntry<Integer, Integer>>>();//AbstractMap.SimpleEntry<Integer,Integer> is similar to pair<int a,int b> in C++ 
      System.out.println("Enter no of Vertices"); 
      int v=in.readInt(); 
      System.out.println("Enter no of Edges"); 
      int e=in.readInt(); 
      Set<Integer>vertices=new HashSet<Integer>(); 
      for(int i=0;i<=v;i++)//Initializing rows for each vertex 
      { 
       vertices.add(i); 
       gr.add(new ArrayList<AbstractMap.SimpleEntry<Integer, Integer>>()); 
      } 
      vertices.remove(0);//Since 0 was added in advertantly 
      System.out.println("Enter <Vertex> <Adjacent Vertex> <Weight>"); 
      for(int i=0;i<e;i++) 
      { 
       int a = in.readInt(); 
       int b = in.readInt(); 
       int c = in.readInt(); 
       gr.get(a).add(new AbstractMap.SimpleEntry<Integer, Integer>(b, c)); 
      } 
      System.out.println("Enter Source"); 
      int s=in.readInt(); 
      Comparator<AbstractMap.SimpleEntry<Integer, Integer>> comparator=new WeightComparator(); 
      TreeSet<AbstractMap.SimpleEntry<Integer, Integer>>ts=new TreeSet<AbstractMap.SimpleEntry<Integer, Integer>>(comparator); 
      int[]d=new int[v+1]; 
      Arrays.fill(d,Integer.MAX_VALUE);//Initial distance INFINITY 
      d[s]=0;//Setting distance of source from source 0 
      vertices.remove(s); 
      for(AbstractMap.SimpleEntry<Integer, Integer> pair:gr.get(s))//Storing vertices adjacent to source 
      { 
       ts.add(pair); 
       d[pair.getKey()]=pair.getValue(); 
      } 
      while(!vertices.isEmpty()&&!ts.isEmpty()) 
      { 
       AbstractMap.SimpleEntry<Integer, Integer> curr=ts.pollFirst();//Removing that element 
       int V=curr.getKey();//Got adjacent vertex; 
       int W=curr.getValue();//Got weight 
       //vertices.remove(); 
       for(AbstractMap.SimpleEntry<Integer, Integer> pair:gr.get(V))//Now traversing vertives adjacent to V 
       { 
        int v1=pair.getKey(); 
        int w1=pair.getValue(); 
        if(d[v1]>W+w1)//setting distance if shorted 
        { 
         d[v1]=W+w1; 
        } 
        ts.add(pair);//Adding to TreeSet 
       } 
       vertices.remove(V);//Removing V from Vertices set 
      } 
      System.out.println("Single Source Shortest Distance from Vertex "+(s)+" is:"); 
      for(int i=1;i<=v;i++) 
      { 
       System.out.println("Shortest Distance from Source Vertex "+s+" is: "+d[i]); 
      } 
     } 

     static public class WeightComparator implements 
       Comparator<AbstractMap.SimpleEntry<Integer, Integer>> 
     { 
      @Override 
      public int compare(AbstractMap.SimpleEntry<Integer, Integer> one, 
           AbstractMap.SimpleEntry<Integer, Integer> two) 
      { 
       return Integer.compare(one.getValue(), two.getValue()); 
      } 
     } 
     //**FAST IO. THAT'S IT. NOTHING DOWN HERE** 
     private static class InputReader 
     { 
      private InputStream stream; 
      private byte[] buf = new byte[1024]; 
      private int curChar; 
      private int numChars; 
      private SpaceCharFilter filter; 

      public InputReader(InputStream stream) 
      { 
       this.stream = stream; 
      } 

      public int read() 
      { 
       if (numChars == -1) 
        throw new InputMismatchException(); 
       if (curChar >= numChars) 
       { 
        curChar = 0; 
        try 
        { 
         numChars = stream.read(buf); 
        } catch (IOException e) 
        { 
         throw new InputMismatchException(); 
        } 
        if (numChars <= 0) 
         return -1; 
       } 
       return buf[curChar++]; 
      } 

      public int readInt() 
      { 
       int c = read(); 
       while (isSpaceChar(c)) 
        c = read(); 
       int sgn = 1; 
       if (c == '-') 
       { 
        sgn = -1; 
        c = read(); 
       } 
       int res = 0; 
       do 
       { 
        if (c < '0' || c > '9') 
         throw new InputMismatchException(); 
        res *= 10; 
        res += c - '0'; 
        c = read(); 
       } while (!isSpaceChar(c)); 
       return res * sgn; 
      } 

      public String readString() 
      { 
       int c = read(); 
       while (isSpaceChar(c)) 
        c = read(); 
       StringBuilder res = new StringBuilder(); 
       do 
       { 
        res.appendCodePoint(c); 
        c = read(); 
       } while (!isSpaceChar(c)); 
       return res.toString(); 
      } 

      public double readDouble() 
      { 
       int c = read(); 
       while (isSpaceChar(c)) 
        c = read(); 
       int sgn = 1; 
       if (c == '-') 
       { 
        sgn = -1; 
        c = read(); 
       } 
       double res = 0; 
       while (!isSpaceChar(c) && c != '.') 
       { 
        if (c == 'e' || c == 'E') 
         return res * Math.pow(10, readInt()); 
        if (c < '0' || c > '9') 
         throw new InputMismatchException(); 
        res *= 10; 
        res += c - '0'; 
        c = read(); 
       } 
       if (c == '.') 
       { 
        c = read(); 
        double m = 1; 
        while (!isSpaceChar(c)) 
        { 
         if (c == 'e' || c == 'E') 
          return res * Math.pow(10, readInt()); 
         if (c < '0' || c > '9') 
          throw new InputMismatchException(); 
         m /= 10; 
         res += (c - '0') * m; 
         c = read(); 
        } 
       } 
       return res * sgn; 
      } 

      public long readLong() 
      { 
       int c = read(); 
       while (isSpaceChar(c)) 
        c = read(); 
       int sgn = 1; 
       if (c == '-') 
       { 
        sgn = -1; 
        c = read(); 
       } 
       long res = 0; 
       do 
       { 
        if (c < '0' || c > '9') 
         throw new InputMismatchException(); 
        res *= 10; 
        res += c - '0'; 
        c = read(); 
       } while (!isSpaceChar(c)); 
       return res * sgn; 
      } 

      public boolean isSpaceChar(int c) 
      { 
       if (filter != null) 
        return filter.isSpaceChar(c); 
       return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1; 
      } 

      public String next() 
      { 
       return readString(); 
      } 

      public interface SpaceCharFilter 
      { 
       public boolean isSpaceChar(int ch); 
      } 
     } 

     private static class OutputWriter 
     { 
      private final PrintWriter writer; 

      public OutputWriter(OutputStream outputStream) 
      { 
       writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream))); 
      } 

      public OutputWriter(Writer writer) 
      { 
       this.writer = new PrintWriter(writer); 
      } 

      public void print(Object... objects) 
      { 
       for (int i = 0; i < objects.length; i++) 
       { 
        if (i != 0) 
         writer.print(' '); 
        writer.print(objects[i]); 
       } 
      } 

      public void printLine(Object... objects) 
      { 
       print(objects); 
       writer.println(); 
      } 

      public void close() 
      { 
       writer.close(); 
      } 

      public void flush() 
      { 
       writer.flush(); 
      } 
     } 
    } 

Я был действительно толкнул, когда я закончил кодирование этого. Мне потребовалось почти 5 часов, чтобы найти все ресурсы и собрать их вместе, чтобы сделать это, но был очень разочарован, когда он не мог своевременно очистить пробные места.

Может ли кто-нибудь пожелать предложить другой способ (возможно, структуру данных)/Оптимизация?

Кроме того, каково время работы этого конкретного алгоритма? К чему вы его изменили? (Если у вас есть)

+0

Разве вы не должны решать проблему самостоятельно, так как [spoj.com] (http://www.spoj.com/) - это сайт для решения проблем с рангом и т. Д. ...? – ericbn

+0

Я не прошу ответа на эту проблему. У меня это уже есть. Я спрашиваю вас, как оптимизировать вышеупомянутое решение. ЭТО ЛЕГКО КОДИРОВАНИЕ В СТАНДАРТНОЙ ADJ MATRIX DIJKSTRA. Если вы видите, на каком уровне я закодировал выше, вы не будете сомневаться в моей способности кодировать последнее или о моих знаниях. – bholagabbar

+0

И меня меньше всего интересуют ряды. Я здесь, чтобы узнать – bholagabbar

ответ

1

Хорошо НАКОНЕЦ! Итак, вот CLEAN и (надеюсь) исполнение FAST Dijkstra.

Как было предложено IVlad и несколько других, вместо того, чтобы использовать:

AbstractMap.SimpleEntry 

Я создал пользовательский тип данных, называемый 'узел', который хранит 2 целые кортежи

Node x=new Node(AdjacentVertex,Weight) 

Я реализован компаратор для этого класса «Узел», который сортирует его в соответствии с назначенными весами. Меньше веса -> Больше приоритета.

И, наконец, мне удалось реализовать очередь приоритетов, которая хранит объекты «Узла» в соответствии с приведенным выше порядком, который устанавливает Компаратор.

Queue<Node> pq=new PriorityQueue<Node>(new Node()); 

Я получил мое решение AC (обслуживаемый) на SPOJ: http://www.spoj.com/status/EZDIJKST,bholagabbar/

Вот код SPOJ (тот же код, как показано ниже, но с более быстрым IO & нет исчерпывающих заявлений): http://ideone.com/p7u5vN

И вырезание до погони, Вот мой Финал, Простой, «Правильный» и оригинальный результат::

import java.util.*; 

/** 
* Created by Shreyans on 4/21/2015 at 6:32 PM using IntelliJ IDEA (Fast IO Template) 
*/ 

class DIJKSTRA 
{ 
    public static void main(String[] args) throws Exception 
    { 
     Scanner sc=new Scanner(System.in); 
     List<ArrayList<Node>> gr=new ArrayList<ArrayList<Node>>();//Initialising Adj list to store graph 
     System.out.println("Enter Number of Vertices"); 
     int v=sc.nextInt(); 
     for(int i=0;i<=v;i++) 
     { 
      gr.add(new ArrayList<Node>()); 
     } 
     System.out.println("Enter Number of Edges"); 
     int e=sc.nextInt(); 
     System.out.println("Enter <Vertex> <Adjacent Vertex> <Weight>"); 
     for(int i=0;i<e;i++) 
     { 
      int a=sc.nextInt(); 
      int b=sc.nextInt(); 
      int c=sc.nextInt(); 
      gr.get(a).add(new Node(b,c)); 
     }//Built Graph 
     System.out.println("Enter Source"); 
     int s=sc.nextInt(); 
     //int des=sc.nextInt();//Entering Destination 
     Queue<Node> pq=new PriorityQueue<Node>(new Node());//Heap to extract value 
     boolean[]checked=new boolean[v+1];//Keeping track of checked values 
     int[]d=new int[v+1];//Keeping track of distances 
     Arrays.fill(d,Integer.MAX_VALUE); 
     d[s]=0; 
     pq.clear(); 
     pq.offer(new Node(s,0)); 
     while(!pq.isEmpty()) 
     { 
      Node x=pq.poll(); 
      int V=x.node;//Getting next node from heap 
      int W=x.cost;//Getting cost 
      checked[V]=true; 
      for(int i=0;i<gr.get(V).size();i++) 
      { 
       Node z=gr.get(V).get(i);//Getting all adjacent Vertices 
       if(!checked[(z.node)])//Not checking visited Vertices 
       { 
        int v1=z.node; 
        int w1=z.cost; 
        if(d[v1]>W+w1)//Checking for min weight 
        { 
         d[v1]=W+w1; 
        } 
        pq.offer(new Node(v1,d[v1]));//Adding element to PriorityQueue 
       } 
      } 
     } 
     for(int i=1;i<=v;i++)//Printing Shortest Distances. Ignore ones with Integer.MAV_VALUE. Meh 
     { 
      if(d[i]==Integer.MAX_VALUE) 
      { 
       System.out.println("No Path connecting Source Vertex "+s+" to Vertex "+i); 
      } 
      else 
      { 
       System.out.println("Shortest distance from Source Vertex "+s+" to Vertex "+i+" is: "+d[i]); 
      } 
     } 
    } 
} 
class Node implements Comparator<Node> 
{ 
    public int node; 
    public int cost; 

    public Node(){} 

    public Node(int node, int cost) 
    { 
     this.node = node; 
     this.cost = cost; 
    } 

    @Override 
    public int compare(Node node1, Node node2) 
    { 
     if (node1.cost < node2.cost) 
      return -1; 
     if (node1.cost > node2.cost) 
      return 1; 
     return 0; 
    } 
} 

Может ли кто-нибудь сказать мне, что такое СОВРЕМЕННОЕ Сложность времени и пространства ЭТОЙ реализации? Мне нужны эти детали для проекта, который я делаю. Могу ли я улучшить свою реализацию? Предложения наиболее приветствуются

+1

Поздравляю, я рад, что это работает. Сложность - это то, о чем я упомянул в своем ответе. Сложность пространства - это «O (N + M)». Вы можете немного улучшить его: избавиться от 'ch', например, вы можете сделать то же самое, что и usd' d': если 'd [node] == Integer.MAX_VALUE', то' node' не был посещен. Нет необходимости в хэш-наборе. Вы можете добавить ту же проверку в свой последний цикл, чтобы избежать комментариев в своем комментарии. – IVlad

+0

Я удалил HashSet и заменил его логическим массивом вроде boolean [] checked = new boolean [v + 1]. Итак, теперь поиск части вершин меньше. Надо немного ускорить – bholagabbar

3
  1. Вы уверены, что ваши функции ввода-вывода на самом деле быстрее, чем Java уже предоставляет?

  2. Код, кажется, O((M + N) log N), с большими константами.Во-первых, потому что вы используете набор, а не приоритетную очередь (например, двоичную кучу), а во-вторых, из-за своего AbstractMap.SimpleEntry, в котором вы создаете множество экземпляров. И тогда из-за вашего списка арраистов, которые также могут быть не очень быстрыми.

В C++ вы можете уйти с ним чаще, чем нет (но не всегда, даже там, и в C++ Дейкстра обычно реализуется с использованием его реализации очереди приоритетов, а не набор его реализации). Для Java, если вы хотите заниматься онлайн-судьями, я предлагаю вам как можно меньше использовать существующие классы, такие как SimpleEntry.

Что бы я сделал, это написать реализацию binary heap и использовать это вместо ваших наборов, избавляясь от всех простых элементов, так как у вас больше возможностей управления с помощью собственной реализации кучи, и вы можете просто использовать простой class Pair { public int node; public int weight; } без каких-либо компараторы.

Если вы не хотите заходить так далеко, возможно, вы можете сначала попробовать заменить свои наборы с помощью собственного PriorityQueue Java (будьте осторожны, используя метод удаления, O(log N)!).

+0

Я тебя слышу. Ребятам из C++ все это удается. В любом случае, есть ли какие-либо ссылки, откуда я могу его забрать? Или вы могли бы его закодировать, и я думаю, что если это сработает, этот вопрос будет сделан с – bholagabbar

+0

@bholagabbar. У меня нет времени писать один, к сожалению, но вы должны иметь возможность находить бинарные реализации кучи в Java. Быстрый поиск придумал это, например: http://stackoverflow.com/questions/18241192/implement-heap-using-a-binary-tree сначала попробуйте приоритетную очередь Java, но она должна быть быстрее. – IVlad

+0

Об IO. Многие хорошие JAVA-кодеры используют этот шаблон. Я тоже поднял его. Его почти так же быстро, как BufferedReader и Scanner, не имеет шансов. Однако, в отличие от BufferedReader, его легче вводить. Мне не нужно брать строку за строкой – bholagabbar

2

Это не алгоритм Дийстра. Алгоритм Дейкстры перечисляет все кратчайшие пути, начиная с источника, в то время как ваш алгоритм перечисляет все пути, начинающиеся с источника, даже содержащие циклы.

Например, рассмотрим граф

1 <----> 2 <----> 3 <----> 4 <----> 5 

Dijstra бы перечислить следующие пути:

[1] 
[1,2] 
[1,2,3] 
[1,2,3,4] 
[1,2,3,4,5] 

в то время как ваш алгоритм перебирает

[1] 
[1,2] 
[1,2,1] 
[1,2,3] 
[1,2,1,2] 
[1,2,3,2] 
[1,2,3,4] 
[1,2,1,2,1] 
[1,2,1,2,3] 
[1,2,3,2,1] 
[1,2,3,2,3] 
[1,2,3,4,3] 
[1,2,3,4,5] 

... и если граф был чем больше, разница будет еще более поразительной. Например, рассмотрим граф, где множество вершин является целыми числами, а две вершины x, y смежны тогда и только тогда, когда x + 1 = y или x = y + 1. Пусть 0 - источник, а n - цель. По построению кратчайший путь от 0 до n имеет длину n. Dijkstra будет посещать все узлы от -n до n ровно один раз. Ваш алгоритм будет посещать все пути длины не более n, из которых 2^n (включая пути, такие как 0,1,0,1,0,1,0,1,0,1, ....). Для n = 20 Dijkstra посетит 41 путь, в то время как ваш код посетит около миллиона!

Поэтому перед тем, как вы будете играть с быстрыми процедурами ввода-вывода или попытайтесь поиграть быстрее, получите правильный алгоритм!

PS: Есть также несколько ошибок, которые делают вашу реализацию неверной, кроме медленной. Например, если у нас есть путь длины n и добавлен шаг длины s, новый путь должен иметь длину n + s, а не s ...

+0

Посмотрите на мой обновленный ответ. И спасибо за указание на ошибки (y) – bholagabbar

Смежные вопросы