// Arup Guha
// 11/6/2006
// Written for COP 3503, to illustarte Dijkstra's Algorithm

import java.io.*;
import java.util.*;

// Keeps track of one vertex in the algorithm.
class point {

	public Integer distance;
	public boolean chosen;
	public int last;

	public point(int d, int source) {
		distance = new Integer(d);
		last = source;
		chosen = false;
	}
}

public class dijkstra2 {

	final static int  MAXINT = 1000000000;

	public static void main(String[] args) throws Exception {

		// Hard-coded - reads in 5 vertex graph from graph.in
		int[][] adj = new int[5][5];
		Scanner fin = new Scanner (new File("graph.in"));
		for (int i = 0; i<25; i++)
			adj[i/5][i%5] = fin.nextInt();
		fin.close();

		// Prints out shortest distances from vertex 0.
		point[] answers = dijkstra(adj, 0);
		for (int i=0; i<5; i++)
			System.out.print(answers[i].distance+" ");
		System.out.println();

		// Prints out the previos vertex on the shortest path to i.
		for (int i=0; i<5; i++)
			System.out.print(answers[i].last+" ");
		System.out.println();

		// Prints out the path from 0 to 1.
		String path = "";
		int end = 4;
		int source = 0;
		while (answers[end].last != source) {
			path = (end + " ") + path;
			end = answers[end].last;
		}
		path = source + " " + end + " " + path;

		System.out.println(path);
	}

	public static point[] dijkstra(int[][] adj, int source) {

		point[] estimates = new point[adj.length];

		// All estimates are infinity.
		for (int i=0; i<estimates.length; i++)
			estimates[i] = new point(MAXINT, source);

		// Our source estimate is 0.
		estimates[source].distance = 0;

		/*** Initial state of estimates array.
		for (int i=0; i<estimates.length; i++)
			System.out.print(estimates[i].last+" ");
		System.out.println();
		***/

		// Number of times algorithm loops.
		for (int i=0; i<estimates.length-1; i++) {

			// Picks next vertex to add into S.
			int vertex = 0;
			int bestseen = MAXINT;

			// In order to be chosen, your estimate has to be
			// minimal and you can never have been chosen before.
			for (int j=0; j<estimates.length; j++) {
				if (estimates[j].chosen == false &&
				    estimates[j].distance < bestseen) {

					bestseen = estimates[j].distance;
					vertex = j;
				}
			}

			// Now we know who we've chosen.
			estimates[vertex].chosen = true;

			// Update estimates to other vertices based on all
			// edges that emanate from vertex.
			for (int j = 0; j<estimates.length; j++) {

				// Is it better to use edge [vertex,j]?
				if (estimates[vertex].distance+adj[vertex][j] <
				    estimates[j].distance) {

				    estimates[j].distance = estimates[vertex].distance + adj[vertex][j];
				    estimates[j].last = vertex;
				}
			}

		}

		// We just return the whole array, so we have access to all shortest distances
		// from vertex 0.
		return estimates;
	}
}