[英]Dijkstra algorithm in weighted graph in Java with big graph
My task is to write a program to calculate shortest time it takes to go from node A(start) to node B(end) on a weighted graph(I'm using dijkstra algorithm). 我的任务是编写一个程序,计算加权图中从节点A(起点)到节点B(终点)所需的最短时间(我正在使用dijkstra算法)。 Time requirement is 2 seconds on memory limit is 64 MB and I can assume that entered data is valid
时间要求为2秒,内存限制为64 MB,我可以假定输入的数据有效
First line has 4 whole numbers: 第一行有4个整数:
Amount of nodes M(2 ≤ M ≤ 20000) 节点数M(2≤M≤20000)
Amount of edges(connections) N(0 ≤ N ≤ 50000) 边(连接)数量N(0≤N≤50000)
Start node A(0 ≤ A < M) and end node O (0 ≤ O < M). 起始节点A(0≤A <M),结束节点O(0≤O <M)。
Next N lines has connection info represented with three whole numbers: 接下来的N行具有以三个整数表示的连接信息:
connected computers and the time between them in milliseconds(edge weight). 连接的计算机及其之间的时间,以毫秒(边缘权重)为单位。 My code doesn't pass all the tests.
我的代码未通过所有测试。 If i test my code with a big graph then it fails as heap memory runs out(about 900MB on my machine).
如果我用一个大图测试我的代码,那么它将失败,因为堆内存用完了(我的机器上大约900MB)。
My problem : How do i optimize my code so it fits into requirements? 我的问题 :如何优化代码以使其符合要求?
Would using adjacency list be enough? 使用邻接表就足够了吗?
My code is this: 我的代码是这样的:
import java.util.ArrayList;
import java.util.Scanner;
public class Route3 {
public static int minDistance(ArrayList<Long> mindist, ArrayList<Boolean> visited){
long min = Long.MAX_VALUE;
int minindex = -1;
for (int i = 0; i < mindist.size(); i++) {
if(!visited.get(i) && (mindist.get(i) <= min)) {
min = mindist.get(i);
minindex = i;
}
}
return minindex;
}
public static long dijkstra(long[][] graph, int start, int end) {
int computers = graph.length;
ArrayList<Boolean> traversed = new ArrayList<>(); //Hold traversed nodes
for (int i = 0; i < computers; i++) {
traversed.add(i,false);
}
ArrayList<Long> mindist = new ArrayList<>(); //Holds mindistances to nodes based on index
for (int i = 0; i < computers; i++) {
mindist.add(i,Long.MAX_VALUE);
}
mindist.set(start,(long)0);
for (int i = 0; i < computers; i++) {
int min = minDistance(mindist,traversed);
if(min == -1) return mindist.get(end);
traversed.set(min,true);
if(min == end) return mindist.get(min) == Long.MAX_VALUE ? -1 : mindist.get(min); //Error check
for (int j = 0; j < computers; j++) {
if(!traversed.get(j) && graph[min][j] != 0 && mindist.get(min) + graph[min][j] < mindist.get(j)) {
mindist.set(j,(mindist.get(min) + graph[min][j]));
}
}
}
return mindist.get(end) == Long.MAX_VALUE ? -1 : mindist.get(end);
}
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int computers = in.nextInt(); //nodes
int connections = in.nextInt(); //edges
int start = in.nextInt();
int end = in.nextInt();
long[][] graph = new long[computers+1][computers+1];
for (int i = 0; i < connections; i++) {
int x = in.nextInt();
int y = in.nextInt();
long t = in.nextLong();
graph[x][y] = t;
graph[y][x] = t;
}
if(connections == 0) {
System.out.println(-1);
System.exit(0);
}
long dist = dijkstra(graph,start,end);
if(dist != -1) System.out.println(dist);
else System.out.println(-1);
}
}
All help is appreciated! 感谢所有帮助!
I think that you'll have to find a better way to hold the graph information. 我认为您必须找到一种更好的方法来保存图形信息。 This line:
这行:
long[][] graph = new long[computers+1][computers+1]
could take up to 20001*20001*8 bytes, that is 3GB! 最多可能占用20001 * 20001 * 8个字节,即3GB!
As your net has few connections per node I'd suggest storing the graph as a HashMap of HashMaps of connections: 由于您的网络每个节点的连接数很少,因此建议将图形存储为连接的HashMaps的HashMap:
class Connection {
int nodeA, nodeB;
long time;
}
HashMap<Integer, HashMap<Integer, Connection>> graph;
It may sound less efficient, but you are saving all the blank edges. 听起来效率较低,但是您要保存所有空白边缘。 Then you add the Connection to the graph indexed by both nodes (nodeA and nodeB):
然后将Connection添加到由两个节点(nodeA和nodeB)索引的图形中:
void addConnection(Connection c)
{
HashMap<Integer, Connection> subgraph = graph.get(c.nodeA);
if(subgraph == null)
subgraph = new HashMap<>();
subgraph.put(c.nodeB, c);
HashMap<Integer, Connection> subgraph = graph.get(c.nodeB);
if(subgraph == null)
subgraph = new HashMap<>();
subgraph.put(c.nodeA, c);
}
And retrieve the connection descriptor like: 并检索连接描述符,例如:
long getConnection(int nodeA, int nodeB)
{
ArrayList<Connection> subgraph = graph.get(nodeA);
if(subgraph == null)
return 0L;
Connection c = subgraph.get(nodeB);
if(c == null)
return 0L;
return c.time;
}
This should make your program slower but much more memory efficient. 这将使您的程序变慢,但内存效率更高。
WARNING: The code is not tested, it's just for clarification. 警告:该代码未经测试,仅供参考。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.