├── .gitignore ├── CSA.java ├── Cargo.toml ├── LICENSE.txt ├── bench.rb ├── bench_data_48h.gz ├── csa.bash ├── csa.c ├── csa.cc ├── csa.go ├── csa.hs ├── csa.js ├── csa.lua ├── csa.pas ├── csa.php ├── csa.py ├── csa.rb ├── csa.rs ├── csa.swift ├── csa_golfed.rb ├── makefile ├── readme.md ├── stations └── test.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.hi 2 | *.o 3 | csa_hs 4 | csa_cpp 5 | csa_go 6 | csa_c 7 | *.class 8 | target/ 9 | Cargo.lock 10 | -------------------------------------------------------------------------------- /CSA.java: -------------------------------------------------------------------------------- 1 | import java.io.*; 2 | import java.util.*; 3 | 4 | class Connection { 5 | int departure_station, arrival_station; 6 | int departure_timestamp, arrival_timestamp; 7 | 8 | // Connection constructor 9 | Connection(String line) { 10 | line.trim(); 11 | String[] tokens = line.split(" "); 12 | 13 | departure_station = Integer.parseInt(tokens[0]); 14 | arrival_station = Integer.parseInt(tokens[1]); 15 | departure_timestamp = Integer.parseInt(tokens[2]); 16 | arrival_timestamp = Integer.parseInt(tokens[3]); 17 | } 18 | }; 19 | 20 | class Timetable { 21 | List connections; 22 | 23 | // Timetable constructor: reads all the connections from stdin 24 | Timetable(BufferedReader in) { 25 | connections = new ArrayList(); 26 | String line; 27 | try { 28 | line = in.readLine(); 29 | 30 | while (!line.isEmpty()) { 31 | connections.add( new Connection(line) ); 32 | line = in.readLine(); 33 | } 34 | } catch( Exception e) { 35 | System.out.println("Something went wrong while reading the data: " + e.getMessage()); 36 | } 37 | } 38 | }; 39 | 40 | public class CSA { 41 | public static final int MAX_STATIONS = 100000; 42 | 43 | Timetable timetable; 44 | Connection in_connection[]; 45 | int earliest_arrival[]; 46 | 47 | CSA(BufferedReader in) { 48 | timetable = new Timetable(in); 49 | } 50 | 51 | void main_loop(int arrival_station) { 52 | int earliest = Integer.MAX_VALUE; 53 | for (Connection connection: timetable.connections) { 54 | if (connection.departure_timestamp >= earliest_arrival[connection.departure_station] && 55 | connection.arrival_timestamp < earliest_arrival[connection.arrival_station]) { 56 | earliest_arrival[connection.arrival_station] = connection.arrival_timestamp; 57 | in_connection[connection.arrival_station] = connection; 58 | 59 | if(connection.arrival_station == arrival_station) { 60 | earliest = Math.min(earliest, connection.arrival_timestamp); 61 | } 62 | } else if(connection.arrival_timestamp > earliest) { 63 | return; 64 | } 65 | } 66 | } 67 | 68 | void print_result(int arrival_station) { 69 | if(in_connection[arrival_station] == null) { 70 | System.out.println("NO_SOLUTION"); 71 | } else { 72 | List route = new ArrayList(); 73 | // We have to rebuild the route from the arrival station 74 | Connection last_connection = in_connection[arrival_station]; 75 | while (last_connection != null) { 76 | route.add(last_connection); 77 | last_connection = in_connection[last_connection.departure_station]; 78 | } 79 | 80 | // And now print it out in the right direction 81 | Collections.reverse(route); 82 | for (Connection connection : route) { 83 | System.out.println(connection.departure_station + " " + connection.arrival_station + " " + 84 | connection.departure_timestamp + " " + connection.arrival_timestamp); 85 | } 86 | } 87 | System.out.println(""); 88 | System.out.flush(); 89 | } 90 | 91 | void compute(int departure_station, int arrival_station, int departure_time) { 92 | in_connection = new Connection[MAX_STATIONS]; 93 | earliest_arrival = new int[MAX_STATIONS]; 94 | for(int i = 0; i < MAX_STATIONS; ++i) { 95 | in_connection[i] = null; 96 | earliest_arrival[i] = Integer.MAX_VALUE; 97 | } 98 | earliest_arrival[departure_station] = departure_time; 99 | 100 | if (departure_station <= MAX_STATIONS && arrival_station <= MAX_STATIONS) { 101 | main_loop(arrival_station); 102 | } 103 | print_result(arrival_station); 104 | } 105 | 106 | public static void main(String[] args) { 107 | BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 108 | CSA csa = new CSA(in); 109 | 110 | String line; 111 | try { 112 | line = in.readLine(); 113 | 114 | while (!line.isEmpty()) { 115 | String[] tokens = line.split(" "); 116 | csa.compute(Integer.parseInt(tokens[0]), Integer.parseInt(tokens[1]), Integer.parseInt(tokens[2])); 117 | line = in.readLine(); 118 | } 119 | } catch( Exception e) { 120 | System.out.println("Something went wrong while reading the parameters: " + e.getMessage()); 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "csa_rs" 3 | version = "0.1.0" 4 | authors = ["Stanislas Signoud "] 5 | 6 | [[bin]] 7 | name = "csa_rs" 8 | path = "csa.rs" 9 | 10 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | -------------------------------------------------------------------------------- /bench.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "zlib" 4 | 5 | if ARGV.size != 1 6 | puts "Usage: ruby #{$0} routing_executable" 7 | exit(-1) 8 | end 9 | 10 | def consume_answer(io) 11 | line = io.gets.strip 12 | if line != "NO_SOLUTION" 13 | while !line.empty? 14 | line = io.gets.strip 15 | end 16 | end 17 | end 18 | 19 | 20 | puts "Loading top stations" 21 | top_stations = File.open("stations").map { |id| id.to_i } 22 | puts "… done\n\n" 23 | 24 | puts "Starting the application" 25 | io = IO.popen ARGV[0], "r+" 26 | puts "… done\n\n" 27 | 28 | puts "Loading the data" 29 | Zlib::GzipReader::open("bench_data_48h.gz").each { |line| io.write line } 30 | io.write "\n" 31 | puts "… done\n\n" 32 | 33 | puts "Starting the benchmark" 34 | count = 0 35 | start_time = Time.now 36 | 37 | top_stations.each do |station| 38 | io.puts "#{station} #{top_stations.first} 0" 39 | consume_answer io 40 | count += 1 41 | end 42 | 43 | io.write "\n" 44 | duration = Time.now - start_time 45 | puts "… done\n\n" 46 | puts "Total time: #{duration} seconds" 47 | puts "Average time per search: #{duration * 1000 / count} ms" 48 | 49 | begin 50 | io.close 51 | rescue Errno::EPIPE 52 | # Prevent broken pipe errors 53 | end 54 | -------------------------------------------------------------------------------- /bench_data_48h.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trainline-eu/csa-challenge/ccdbbd0c6fd9fcdff64631149284898502f05e56/bench_data_48h.gz -------------------------------------------------------------------------------- /csa.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | compute() { 4 | local earliest_arr in_conn route infinity 5 | trip_dep=$1 6 | trip_arr=$2 7 | earliest_arr[$trip_dep]=$3 8 | 9 | while read dep arr dep_ts arr_ts; do 10 | infinity=$((arr_ts + 1)) 11 | if [ $dep_ts -ge ${earliest_arr[$dep]-$infinity} ] && \ 12 | [ $arr_ts -lt ${earliest_arr[$arr]-$infinity} ]; then 13 | earliest_arr[$arr]=$arr_ts 14 | in_conn[$arr]="$dep $arr $dep_ts $arr_ts" 15 | elif [ $dep_ts -ge ${earliest_arr[$trip_arr]-$infinity} ]; then 16 | break 17 | fi 18 | done <<< "$timetable" 19 | 20 | if [ -z "${in_conn[$trip_arr]}" ]; then 21 | echo NO_SOLUTION 22 | else 23 | while [ $trip_arr -ne $trip_dep ]; do 24 | set -- ${in_conn[$trip_arr]} 25 | route=$@'\n'$route 26 | trip_arr=$1 27 | done 28 | echo -e $route 29 | fi 30 | } 31 | 32 | timetable=$(while read conn; do 33 | [ -z "$conn" ] && break || echo $conn 34 | done) 35 | 36 | while read trip; do 37 | [ -z "$trip" ] && break || compute $trip 38 | done 39 | -------------------------------------------------------------------------------- /csa.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #if DEBUG 8 | #define eprintf(format, args...) do{ fprintf(stderr, format , ## args); fflush(stderr); }while(0); 9 | #else 10 | #define eprintf(format, args...) 11 | #endif 12 | 13 | // Generic Arrays in C \o/ 14 | 15 | #define array_of(type) type##_array 16 | #define define_array_of(type) typedef struct { size_t capacity; size_t count; type * values; } array_of(type); 17 | #define array_at(array,i) array->values[i] 18 | #define array_new_entry(array) ({\ 19 | if ((array)->count==(array)->capacity) {\ 20 | const size_t BLOCK = 4*1024*1024;\ 21 | (array)->capacity+=BLOCK;\ 22 | (array)->values = realloc((array)->values, (array)->capacity*sizeof((array)->values[0]));\ 23 | eprintf("realloced to %zu\n",(array)->capacity);\ 24 | }\ 25 | (array)->count++;\ 26 | &((array)->values[(array)->count-1]);\ 27 | }) 28 | 29 | // Generic raw structure access 30 | 31 | void _raw_parse(char* line, unsigned int * raw, size_t capacity) { 32 | char *token; size_t i=0; 33 | while ((token = strsep(&line, " ")) && ifrom] = rq->start; 82 | 83 | // main loop 84 | timestamp earliest = INFINITE; 85 | for (connection_index i = 0; i < timetable->count; ++i) { 86 | connection * c = &array_at(timetable,i); 87 | if (c->start >= earliest_arrival[c->from] && c->end < earliest_arrival[c->to]) { 88 | earliest_arrival[c->to] = c->end; 89 | in_connection[c->to] = i; 90 | 91 | if(c->to == rq->to) { 92 | earliest = MIN(earliest, c->end); 93 | } 94 | } else if(c->end > earliest) { 95 | break; 96 | } 97 | } 98 | 99 | // print result 100 | if(in_connection[rq->to] == INFINITE) { 101 | printf("NO_SOLUTION\n"); 102 | } else { 103 | connection_index route[300]; 104 | connection_index last_connection = in_connection[rq->to]; 105 | int i = 0; 106 | while (last_connection != INFINITE) { 107 | route[i++] = last_connection; 108 | last_connection = in_connection[array_at(timetable,last_connection).from]; 109 | } 110 | 111 | for (i--; i>=0; i--) { 112 | raw_printf(&array_at(timetable, route[i])); 113 | } 114 | } 115 | printf("\n"); 116 | fflush(stdout); 117 | } 118 | 119 | // Main I/O 120 | 121 | int main() 122 | { 123 | array_of(connection) timetable = {0,0,NULL}; 124 | 125 | enum { LOAD, COMPUTE } mode = LOAD; 126 | char * line = NULL; size_t line_cap = 0; ssize_t linelen; 127 | while ((linelen = getline(&line,&line_cap,stdin))>0) { 128 | if(strcmp(line,"\n")==0) { 129 | eprintf( "%zu connections",t.count); 130 | mode = COMPUTE; 131 | } else { 132 | switch (mode) { 133 | case LOAD: { 134 | raw_parse(line, array_new_entry(&timetable)); 135 | break; 136 | } 137 | case COMPUTE: { 138 | request rq; 139 | raw_parse(line, &rq); 140 | compute_route(&timetable,&rq); 141 | break; 142 | } 143 | } 144 | } 145 | } 146 | free(line); 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /csa.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | const int MAX_STATIONS = 100000; 8 | const uint32_t INF = std::numeric_limits::max(); 9 | 10 | struct Connection { 11 | uint32_t departure_station, arrival_station; 12 | uint32_t departure_timestamp, arrival_timestamp; 13 | 14 | // Connection constructor 15 | Connection(std::string line) { 16 | boost::trim(line); 17 | std::vector tokens; 18 | boost::split(tokens, line, boost::is_any_of(" ")); 19 | 20 | departure_station = std::stoi(tokens[0]); 21 | arrival_station = std::stoi(tokens[1]); 22 | departure_timestamp = std::stoi(tokens[2]); 23 | arrival_timestamp = std::stoi(tokens[3]); 24 | } 25 | }; 26 | 27 | struct Timetable { 28 | std::vector connections; 29 | 30 | // Timetable constructor: reads all the connections from stdin 31 | Timetable() { 32 | std::string line; 33 | getline(std::cin, line); 34 | 35 | while (!line.empty()) { 36 | connections.push_back( Connection(line) ); 37 | getline(std::cin, line); 38 | } 39 | } 40 | }; 41 | 42 | struct CSA { 43 | Timetable timetable; 44 | std::vector in_connection; 45 | std::vector earliest_arrival; 46 | 47 | void main_loop(uint32_t arrival_station) { 48 | uint32_t earliest = INF; 49 | for (size_t i = 0; i < timetable.connections.size(); ++i) { 50 | Connection connection = timetable.connections[i]; 51 | 52 | if (connection.departure_timestamp >= earliest_arrival[connection.departure_station] && 53 | connection.arrival_timestamp < earliest_arrival[connection.arrival_station]) { 54 | earliest_arrival[connection.arrival_station] = connection.arrival_timestamp; 55 | in_connection[connection.arrival_station] = i; 56 | 57 | if(connection.arrival_station == arrival_station) { 58 | earliest = std::min(earliest, connection.arrival_timestamp); 59 | } 60 | } else if(connection.arrival_timestamp > earliest) { 61 | return; 62 | } 63 | } 64 | } 65 | 66 | void print_result(uint32_t arrival_station) { 67 | if(in_connection[arrival_station] == INF) { 68 | std::cout << "NO_SOLUTION" << std::endl; 69 | } else { 70 | std::vector route; 71 | // We have to rebuild the route from the arrival station 72 | uint32_t last_connection_index = in_connection[arrival_station]; 73 | while (last_connection_index != INF) { 74 | Connection connection = timetable.connections[last_connection_index]; 75 | route.push_back(connection); 76 | last_connection_index = in_connection[connection.departure_station]; 77 | } 78 | 79 | // And now print it out in the right direction 80 | std::reverse(route.begin(), route.end()); 81 | for (auto connection : route) { 82 | std::cout << connection.departure_station << " " << connection.arrival_station << " " << 83 | connection.departure_timestamp << " " << connection.arrival_timestamp << std::endl; 84 | } 85 | } 86 | std::cout << std::endl; 87 | } 88 | 89 | void compute(uint32_t departure_station, uint32_t arrival_station, uint32_t departure_time) { 90 | in_connection.assign(MAX_STATIONS, INF); 91 | earliest_arrival.assign(MAX_STATIONS, INF); 92 | earliest_arrival[departure_station] = departure_time; 93 | 94 | if (departure_station <= MAX_STATIONS && arrival_station <= MAX_STATIONS) { 95 | main_loop(arrival_station); 96 | } 97 | print_result(arrival_station); 98 | } 99 | }; 100 | 101 | int main(int, char**) { 102 | CSA csa; 103 | 104 | std::string line; 105 | std::vector tokens; 106 | getline(std::cin, line); 107 | 108 | while (!line.empty()) { 109 | boost::split(tokens, line, boost::is_any_of(" ")); 110 | csa.compute(std::stoi(tokens[0]), std::stoi(tokens[1]), std::stoi(tokens[2])); 111 | getline(std::cin, line); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /csa.go: -------------------------------------------------------------------------------- 1 | // gofmt -w=true *.go && go build -o csa-go csa.go && ruby test.rb ./csa-go 2 | 3 | package main 4 | 5 | import ( 6 | "bufio" 7 | "fmt" 8 | "math" 9 | "os" 10 | ) 11 | 12 | const maxStations = 100000 13 | const infinity = math.MaxUint32 14 | 15 | type Connection struct { 16 | departureStation uint32 17 | arrivalStation uint32 18 | departureTime uint32 19 | arrivalTime uint32 20 | } 21 | 22 | type Timetable []Connection 23 | 24 | func readTimetable(scanner *bufio.Scanner) Timetable { 25 | timetable := make([]Connection, 0) 26 | 27 | for scanner.Scan() { 28 | if len(scanner.Text()) == 0 { 29 | break 30 | } else { 31 | connection := Connection{} 32 | _, err := fmt.Sscanln( 33 | scanner.Text(), 34 | &connection.departureStation, 35 | &connection.arrivalStation, 36 | &connection.departureTime, 37 | &connection.arrivalTime) 38 | if err != nil { 39 | panic(err) 40 | } 41 | timetable = append(timetable, connection) 42 | } 43 | } 44 | 45 | return timetable 46 | } 47 | 48 | func (timetable Timetable) compute(departureStation uint32, arrivalStation uint32, departureTime uint32) { 49 | // initialization 50 | inConnection := make([]uint32, maxStations, maxStations) 51 | earliestArrival := make([]uint32, maxStations, maxStations) 52 | 53 | for i := 0; i < maxStations; i++ { 54 | inConnection[i] = infinity 55 | earliestArrival[i] = infinity 56 | } 57 | 58 | // main loop 59 | earliestArrival[departureStation] = departureTime 60 | for i, connection := range timetable { 61 | if connection.departureTime >= earliestArrival[connection.departureStation] && 62 | connection.arrivalTime < earliestArrival[connection.arrivalStation] { 63 | 64 | inConnection[connection.arrivalStation] = uint32(i) 65 | earliestArrival[connection.arrivalStation] = connection.arrivalTime 66 | } 67 | } 68 | 69 | // print result 70 | if inConnection[arrivalStation] == infinity { 71 | fmt.Println("NO_SOLUTION") 72 | } else { 73 | route := make([]Connection, 0) 74 | 75 | for lastConnectionIndex := inConnection[arrivalStation]; lastConnectionIndex != infinity; { 76 | connection := timetable[lastConnectionIndex] 77 | route = append(route, connection) 78 | lastConnectionIndex = inConnection[connection.departureStation] 79 | } 80 | 81 | for i := len(route) - 1; i >= 0; i-- { 82 | fmt.Printf("%d %d %d %d\n", route[i].departureStation, route[i].arrivalStation, route[i].departureTime, route[i].arrivalTime) 83 | } 84 | 85 | fmt.Println("") 86 | } 87 | 88 | } 89 | 90 | func main() { 91 | scanner := bufio.NewScanner(os.Stdin) 92 | 93 | timetable := readTimetable(scanner) 94 | 95 | var departureStation, arrivalStation, departureTime uint32 96 | for scanner.Scan() { 97 | if len(scanner.Text()) == 0 { 98 | os.Exit(0) 99 | } else { 100 | _, err := fmt.Sscanln(scanner.Text(), &departureStation, &arrivalStation, &departureTime) 101 | if err != nil { 102 | panic(err) 103 | } 104 | timetable.compute(departureStation, arrivalStation, departureTime) 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /csa.hs: -------------------------------------------------------------------------------- 1 | import System.IO 2 | import qualified Data.Map as M 3 | import Data.Maybe (fromMaybe, fromJust) 4 | import Control.Applicative 5 | import Control.Monad (unless) 6 | import Numeric 7 | import qualified Data.ByteString.Char8 as BS (ByteString, getLine, readInt, words, null) 8 | 9 | readInts :: BS.ByteString -> [Int] 10 | readInts = map (fst . fromJust . BS.readInt) . BS.words 11 | 12 | type Station = Int 13 | 14 | type Timestamp = Int 15 | 16 | infinity :: Timestamp 17 | infinity = maxBound 18 | 19 | -- Evaluate Maybe Timestamp with infinity as fallback 20 | timestamp :: Maybe Timestamp -> Timestamp 21 | timestamp = fromMaybe infinity 22 | 23 | -- Connection 24 | -- departureStation arrivalStation departureTime arrivalTime 25 | data Connection = Connection Station Station Timestamp Timestamp 26 | 27 | newConnection :: [Int] -> Connection 28 | newConnection [departure, arrival, departureTime, arrivalTime] = 29 | Connection departure arrival departureTime arrivalTime 30 | newConnection _ = error "Illegal Connection values" 31 | 32 | parseConnection :: BS.ByteString -> Connection 33 | parseConnection = newConnection.readInts 34 | 35 | printConnection :: Connection -> String 36 | printConnection (Connection departure arrival departureTime arrivalTime) = 37 | unwords . map show $ [departure, arrival, departureTime, arrivalTime] 38 | 39 | -- Query 40 | -- departureStation arrivalStation departureTime 41 | data Query = Query Station Station Timestamp 42 | 43 | newQuery :: [Int] -> Query 44 | newQuery [departure, arrival, departureTime] = Query departure arrival departureTime 45 | newQuery _ = error "Illegal Query values" 46 | 47 | parseQuery :: BS.ByteString -> Query 48 | parseQuery = newQuery.readInts 49 | 50 | -- Timetable 51 | -- arrivalTimes inConnections 52 | data Timetable = Timetable IndexedTimestamps IndexedConnections 53 | 54 | type IndexedTimestamps = M.Map Station Timestamp 55 | type IndexedConnections = M.Map Station Connection 56 | 57 | emptyTimetable :: Query -> Timetable 58 | emptyTimetable (Query departure _ departureTime) = 59 | Timetable (M.insert departure departureTime M.empty) M.empty 60 | 61 | buildTimetable :: Query -> [Connection] -> Timetable 62 | buildTimetable = (augmentTimetable infinity) .emptyTimetable 63 | 64 | augmentTimetable :: Timestamp -> Timetable -> [Connection] -> Timetable 65 | augmentTimetable _ timetable [] = timetable 66 | augmentTimetable earliestArrival timetable@(Timetable arrivalTimes inConnections) (connection : connections) = 67 | let Connection departure arrival departureTime arrivalTime = connection 68 | bestDepartureTime = timestamp $ M.lookup departure arrivalTimes 69 | bestArrivalTime = timestamp $ M.lookup arrival arrivalTimes 70 | in 71 | if bestDepartureTime <= departureTime && bestArrivalTime > arrivalTime 72 | then 73 | let newArrivalTimes = M.insert arrival arrivalTime arrivalTimes 74 | newInConnections = M.insert arrival connection inConnections 75 | newTimetable = Timetable newArrivalTimes newInConnections 76 | in augmentTimetable (min arrivalTime earliestArrival) newTimetable connections 77 | else 78 | if arrivalTime > earliestArrival 79 | then 80 | timetable 81 | else 82 | augmentTimetable earliestArrival timetable connections 83 | 84 | -- CSA implementation 85 | findPath :: Timetable -> Query -> Path 86 | findPath (Timetable _ inConnections) (Query _ arrival _) = findPathImpl inConnections arrival [] 87 | 88 | type Path = [Connection] 89 | 90 | findPathImpl :: IndexedConnections -> Station -> [Connection] -> [Connection] 91 | findPathImpl inConnections objective accumulator = 92 | case M.lookup objective inConnections of 93 | Nothing -> accumulator 94 | Just connection -> 95 | let Connection departure _ _ _ = connection 96 | in findPathImpl inConnections departure (connection : accumulator) 97 | 98 | readConnections :: IO [BS.ByteString] 99 | readConnections = do 100 | line <- BS.getLine 101 | if BS.null line 102 | then return [] 103 | else (line :) <$> readConnections 104 | 105 | printPath :: Path -> IO () 106 | printPath [] = putStrLn "NO_SOLUTION" 107 | printPath path = mapM_ (putStrLn . printConnection) path 108 | 109 | mainLoop :: [Connection] -> IO () 110 | mainLoop connections = do 111 | done <- isEOF 112 | unless done $ do 113 | line <- BS.getLine 114 | unless (BS.null line) $ do 115 | let query = parseQuery line 116 | let timetable = buildTimetable query connections 117 | 118 | printPath $ findPath timetable query 119 | putStrLn "" 120 | hFlush stdout 121 | 122 | mainLoop connections 123 | 124 | -- main 125 | main :: IO () 126 | main = do 127 | firstLines <- readConnections 128 | let connections = fmap parseConnection firstLines 129 | 130 | mainLoop connections 131 | -------------------------------------------------------------------------------- /csa.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict' 4 | 5 | const DEP = 0, ARR = 1, DEP_TS = 2, ARR_TS = 3 6 | const MAX_STATION = 100000 7 | const INFINITY = Math.pow(2, 32) - 1 8 | 9 | let timetable = new Uint32Array(4) 10 | let timetableLength = 0 // Actual number of elements in 'timetable' 11 | 12 | const inConn = new Uint32Array(MAX_STATION) 13 | const earliestArr = new Uint32Array(MAX_STATION) 14 | 15 | function compute(trip) { // Crankshaft-optimizable (Node v5.0.0) 16 | let route = [] 17 | let station 18 | 19 | inConn.fill(INFINITY) 20 | earliestArr.fill(INFINITY) 21 | earliestArr[trip[DEP]] = trip[DEP_TS] 22 | 23 | for (let i = 0 ; i < timetableLength ; i = i + 4 /* [1] */) { 24 | // [1]: Crankshaft doesn't support let compound assignements ('i += 4'). 25 | if ( 26 | timetable[i + DEP_TS] >= earliestArr[timetable[i + DEP]] && 27 | timetable[i + ARR_TS] < earliestArr[timetable[i + ARR]] 28 | ) { 29 | inConn[timetable[i + ARR]] = i 30 | earliestArr[timetable[i + ARR]] = timetable[i + ARR_TS] 31 | } else if (timetable[i + DEP_TS] > earliestArr[trip[ARR]]) { 32 | break 33 | } 34 | } 35 | 36 | if (inConn[trip[ARR]] === INFINITY) { 37 | return null 38 | } 39 | 40 | station = trip[ARR] 41 | while (station !== trip[DEP]) { 42 | route.unshift(timetable.slice(inConn[station], inConn[station] + 4)) 43 | station = route[0][DEP] 44 | } 45 | 46 | return route 47 | } 48 | 49 | let initializing = true 50 | require('readline') 51 | .createInterface({ input: process.stdin }) 52 | .on('line', function (line) { 53 | if (!line) { 54 | if (!initializing) { 55 | this.close() 56 | } 57 | initializing = false 58 | return 59 | } 60 | 61 | let connOrTrip = Uint32Array.from(line.split(' ')) 62 | if (initializing) { 63 | if (timetable.length === timetableLength) { 64 | let aux = new Uint32Array(timetable.length << 1) 65 | aux.set(timetable) 66 | timetable = aux 67 | } 68 | timetable.set(connOrTrip, timetableLength) 69 | timetableLength += 4 70 | } else { 71 | let route = compute(connOrTrip) 72 | 73 | if (route) { 74 | console.log(route.map((c) => c.join(' ')).join('\n'), '\n') 75 | } else { 76 | console.log('NO_SOLUTION') 77 | } 78 | } 79 | }) 80 | -------------------------------------------------------------------------------- /csa.lua: -------------------------------------------------------------------------------- 1 | #!/usr/local/bin/luajit 2 | function main() 3 | -- Load data 4 | connections = {} 5 | for line in io.lines() do 6 | if line == "" then break end 7 | for value in string.gmatch(line, "%d+") do 8 | connections[#connections+1] = tonumber(value) 9 | end 10 | end 11 | -- Load queries 12 | in_conn = {} 13 | earliest_arr = {} 14 | for departure, arrival, departure_time in io.input():lines("*n", "*n", "*n") do 15 | for i = 1, MAX_STATION do 16 | in_conn[i] = INFINITY 17 | earliest_arr[i] = INFINITY 18 | end 19 | earliest_arr[departure] = departure_time 20 | if departure <= MAX_STATION and arrival <= MAX_STATION then 21 | find(connections, earliest_arr, in_conn, arrival) 22 | end 23 | print_result(connections, earliest_arr, in_conn, arrival) 24 | end 25 | end 26 | 27 | MAX_STATION = 100000 28 | INFINITY = 16777216 --math.maxinteger (Lua 5.3) 29 | function find(connections, earliest_arr, in_conn, arr) 30 | earliest = INFINITY 31 | for i = 1, #connections, 4 do 32 | -- connection departure / arrival stations and time 33 | cds = connections[i] 34 | cas = connections[i + 1] 35 | cdt = connections[i + 2] 36 | cat = connections[i + 3] 37 | if cdt >= earliest_arr[cds] and cat < earliest_arr[cas] then 38 | earliest_arr[cas] = cat 39 | in_conn[cas] = i 40 | if cas == arr then 41 | earliest = math.min(earliest, cat) 42 | end 43 | elseif cat > earliest then 44 | return 45 | end 46 | end 47 | end 48 | 49 | function print_result(connections, earliest_arr, in_conn, arr) 50 | if in_conn[arr] == INFINITY then 51 | print("NO_SOLUTION") 52 | else 53 | route = {} 54 | last_conn_i = in_conn[arr] 55 | while last_conn_i ~= INFINITY do 56 | route[#route+1] = last_conn_i 57 | cds = connections[last_conn_i] 58 | last_conn_i = in_conn[cds] 59 | end 60 | -- The route goes from the arrival to the departure. 61 | rev_route = {} 62 | for i = 1, #route do 63 | rev_route[#rev_route+1] = route[#route - i + 1] 64 | end 65 | -- Print it. 66 | for i = 1, #rev_route do 67 | conn_i = rev_route[i] 68 | -- Departure station, arrival station, departure time, arrival time. 69 | print(connections[conn_i] .. " " .. connections[conn_i+1] .. " " .. 70 | connections[conn_i+2] .. " " .. connections[conn_i+3]) 71 | end 72 | end 73 | print() 74 | io.flush() 75 | end 76 | 77 | main() 78 | -------------------------------------------------------------------------------- /csa.pas: -------------------------------------------------------------------------------- 1 | program csa; 2 | {$mode objfpc} 3 | uses 4 | Math, SysUtils, Classes; 5 | 6 | const 7 | MAX_STATIONS = 100000; 8 | INFINITY = 4294967295; 9 | 10 | type 11 | TConnection = record 12 | departureStation: Longword; 13 | arrivalStation: Longword; 14 | departureTime: Longword; 15 | arrivalTime: Longword; 16 | end; 17 | TTimetable = array of TConnection; 18 | TMyArray = array[0..MAX_STATIONS] of Longword; 19 | 20 | var 21 | stdin, stdout: text; 22 | i: Longword; 23 | max: Longword; 24 | line: string; 25 | fields: TStringList; 26 | connection: TConnection; 27 | timetable: TTimetable; 28 | inConnection: TMyArray; 29 | earliestArrival: TMyArray; 30 | 31 | procedure mainLoop(arrivalStation: Longword); 32 | var 33 | earliest: Longword; 34 | begin 35 | earliest := INFINITY; 36 | for i := 0 to max-1 do 37 | begin 38 | if (timetable[i].departureTime >= earliestArrival[timetable[i].departureStation]) AND (timetable[i].arrivalTime < earliestArrival[timetable[i].arrivalStation]) then 39 | begin 40 | earliestArrival[timetable[i].arrivalStation] := timetable[i].arrivalTime; 41 | inConnection[timetable[i].arrivalStation] := i; 42 | if (timetable[i].arrivalStation = arrivalStation) then 43 | earliest := min(timetable[i].arrivalTime, earliest); 44 | end 45 | else if (timetable[i].arrivalTime > earliest) then 46 | Exit; 47 | end; 48 | end; 49 | 50 | procedure printResult(arrivalStation: Longword); 51 | var 52 | lastConnectionIndex: Longword; 53 | route: TTimetable; 54 | maxRoute: Longword; 55 | begin 56 | if inConnection[arrivalStation] = INFINITY then 57 | begin 58 | WriteLn(stdout, 'NO_SOLUTION'); 59 | end 60 | else 61 | begin 62 | lastConnectionIndex := inConnection[arrivalStation]; 63 | i := 0; 64 | while (lastConnectionIndex <> INFINITY) do 65 | begin 66 | connection := timetable[lastConnectionIndex]; 67 | lastConnectionIndex := inConnection[connection.departureStation]; 68 | SetLength(route, i+1); 69 | route[i] := connection; 70 | i := i + 1; 71 | end; 72 | maxRoute := i; 73 | for i := maxRoute-1 downto 0 do 74 | WriteLn(stdout, route[i].departureStation, ' ', route[i].arrivalStation, ' ', route[i].departureTime, ' ', route[i].arrivalTime); 75 | end; 76 | WriteLn(stdout, ''); 77 | Flush(stdout); 78 | end; 79 | 80 | procedure compute(departureStation, arrivalStation, departureTime: Longword); 81 | begin 82 | FillDWord(inConnection, MAX_STATIONS, INFINITY); 83 | FillDWord(earliestArrival, MAX_STATIONS, INFINITY); 84 | earliestArrival[departureStation] := departureTime; 85 | 86 | if (departureStation <= MAX_STATIONS) AND (arrivalStation <= MAX_STATIONS) then 87 | mainLoop(arrivalStation); 88 | printResult(arrivalStation); 89 | end; 90 | 91 | begin 92 | assign(stdin, ''); 93 | assign(stdout, ''); 94 | reset(stdin); 95 | rewrite(stdout); 96 | fields := TStringList.Create; 97 | fields.Delimiter := ' '; 98 | i := 0; 99 | while not eof(stdin) do 100 | begin 101 | ReadLn(stdin, line); 102 | if (line = '') then 103 | break; 104 | fields.DelimitedText := line; 105 | connection.departureStation := StrToInt(fields[0]); 106 | connection.arrivalStation := StrToInt(fields[1]); 107 | connection.departureTime := StrToInt(fields[2]); 108 | connection.arrivalTime := StrToInt(fields[3]); 109 | SetLength(timetable, i+1); 110 | timetable[i] := connection; 111 | i := i + 1; 112 | end; 113 | max := i; 114 | while not eof(stdin) do 115 | begin 116 | ReadLn(stdin, line); 117 | if (line = '') then 118 | continue; 119 | fields.DelimitedText := line; 120 | connection.departureStation := StrToInt(fields[0]); 121 | connection.arrivalStation := StrToInt(fields[1]); 122 | connection.departureTime := StrToInt(fields[2]); 123 | compute(connection.departureStation, connection.arrivalStation, connection.departureTime); 124 | end; 125 | Close(stdin); 126 | Close(stdout); 127 | end. 128 | -------------------------------------------------------------------------------- /csa.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | $connection) { 27 | if ( 28 | $connection[DEPARTURE_TIME] >= $earliestArrival[$connection[DEPARTURE_STATION]] && 29 | $connection[ARRIVAL_TIME] < $earliestArrival[$connection[ARRIVAL_STATION]] 30 | ) { 31 | $inConnection[$connection[ARRIVAL_STATION]] = $i; 32 | $earliestArrival[$connection[ARRIVAL_STATION]] = $connection[ARRIVAL_TIME]; 33 | } 34 | } 35 | 36 | if ($inConnection[$arrivalStation] === PHP_INT_MAX) { 37 | echo "NO_SOLUTION\n"; 38 | return; 39 | } 40 | $route = []; 41 | $lastConnectionIndex = $inConnection[$arrivalStation]; 42 | while ($lastConnectionIndex !== PHP_INT_MAX) { 43 | $connection = $timetable[$lastConnectionIndex]; 44 | $route[] = $connection; 45 | $lastConnectionIndex = $inConnection[$connection[DEPARTURE_STATION]]; 46 | } ; 47 | 48 | foreach (array_reverse($route) as $row) { 49 | printf("%d %d %d %d\n", $row[DEPARTURE_STATION], $row[ARRIVAL_STATION], $row[DEPARTURE_TIME], $row[ARRIVAL_TIME]); 50 | } 51 | echo "\n"; 52 | } 53 | 54 | $fh = fopen('php://stdin', 'r'); 55 | $timetable = readTimetable($fh); 56 | 57 | while (($line = fgets($fh, 128)) !== false) { 58 | if ($line !== "\n") { 59 | list($departureStation, $arrivalStation, $departureTime) = array_map('intval', explode(' ', $line)); 60 | compute($timetable, $departureStation, $arrivalStation, $departureTime); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /csa.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | from array import array 5 | 6 | MAX_STATIONS = 100000 7 | MAX_INT = 2**32 - 1 8 | 9 | 10 | class Connection: 11 | def __init__(self, line): 12 | tokens = line.split(" ") 13 | 14 | self.departure_station = int(tokens[0]) 15 | self.arrival_station = int(tokens[1]) 16 | self.departure_timestamp = int(tokens[2]) 17 | self.arrival_timestamp = int(tokens[3]) 18 | 19 | 20 | class Timetable: 21 | # reads all the connections from stdin 22 | def __init__(self): 23 | self.connections = [] 24 | 25 | for line in sys.stdin: 26 | if line.rstrip() == "": 27 | break 28 | 29 | self.connections.append(Connection(line.rstrip())) 30 | 31 | 32 | class CSA: 33 | def __init__(self): 34 | self.timetable = Timetable() 35 | self.in_connection = array('I') 36 | self.earliest_arrival = array('I') 37 | 38 | def main_loop(self, arrival_station): 39 | earliest = MAX_INT 40 | 41 | for i, c in enumerate(self.timetable.connections): 42 | if c.departure_timestamp >= self.earliest_arrival[c.departure_station] \ 43 | and c.arrival_timestamp < self.earliest_arrival[c.arrival_station]: 44 | self.earliest_arrival[c.arrival_station] = c.arrival_timestamp 45 | self.in_connection[c.arrival_station] = i 46 | 47 | if c.arrival_station == arrival_station: 48 | earliest = min(earliest, c.arrival_timestamp) 49 | elif c.arrival_timestamp > earliest: 50 | return 51 | 52 | def print_result(self, arrival_station): 53 | if self.in_connection[arrival_station] == MAX_INT: 54 | print("NO_SOLUTION") 55 | else: 56 | route = [] 57 | 58 | # We have to rebuild the route from the arrival station 59 | last_connection_index = self.in_connection[arrival_station] 60 | 61 | while last_connection_index != MAX_INT: 62 | connection = self.timetable.connections[last_connection_index] 63 | route.append(connection) 64 | last_connection_index = self.in_connection[connection.departure_station] 65 | 66 | # And now print it out in the right direction 67 | for c in reversed(route): 68 | print("{} {} {} {}".format( 69 | c.departure_station, 70 | c.arrival_station, 71 | c.departure_timestamp, 72 | c.arrival_timestamp 73 | )) 74 | 75 | print("") 76 | try: 77 | sys.stdout.flush() 78 | except BrokenPipeError: 79 | pass 80 | 81 | def compute(self, departure_station, arrival_station, departure_time): 82 | self.in_connection = array('I', [MAX_INT for _ in range(MAX_STATIONS)]) 83 | self.earliest_arrival = array('I', [MAX_INT for _ in range(MAX_STATIONS)]) 84 | 85 | self.earliest_arrival[departure_station] = departure_time 86 | 87 | if departure_station <= MAX_STATIONS and arrival_station <= MAX_STATIONS: 88 | self.main_loop(arrival_station) 89 | 90 | self.print_result(arrival_station) 91 | 92 | 93 | def main(): 94 | csa = CSA() 95 | 96 | for line in sys.stdin: 97 | if line.rstrip() == "": 98 | break 99 | 100 | tokens = line.rstrip().split(" ") 101 | csa.compute(int(tokens[0]), int(tokens[1]), int(tokens[2])) 102 | 103 | sys.stdin.close() 104 | 105 | if __name__ == '__main__': 106 | main() 107 | -------------------------------------------------------------------------------- /csa.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | MAX_STATIONS = 100000 4 | INF = 1.0/0 5 | 6 | class Connection 7 | attr_reader :departure_station, :arrival_station, 8 | :departure_timestamp, :arrival_timestamp 9 | 10 | def initialize(line) 11 | tokens = line.split(" ") 12 | 13 | @departure_station = tokens[0].to_i 14 | @arrival_station = tokens[1].to_i 15 | @departure_timestamp = tokens[2].to_i 16 | @arrival_timestamp = tokens[3].to_i 17 | end 18 | end 19 | 20 | class Timetable 21 | attr_reader :connections 22 | 23 | # reads all the connections from stdin 24 | def initialize 25 | @connections = [] 26 | line = STDIN.gets.strip 27 | 28 | while !line.empty? 29 | @connections << Connection.new(line) 30 | line = STDIN.gets.strip 31 | end 32 | end 33 | end 34 | 35 | class CSA 36 | attr_reader :timetable, :in_connection, :earliest_arrival 37 | 38 | def initialize 39 | @timetable = Timetable.new 40 | end 41 | 42 | def main_loop(arrival_station) 43 | earliest = INF 44 | timetable.connections.each_with_index do |c, i| 45 | if c.departure_timestamp >= earliest_arrival[c.departure_station] && c.arrival_timestamp < earliest_arrival[c.arrival_station] 46 | earliest_arrival[c.arrival_station] = c.arrival_timestamp 47 | in_connection[c.arrival_station] = i 48 | if c.arrival_station == arrival_station 49 | earliest = [earliest, c.arrival_timestamp].min 50 | end 51 | elsif c.arrival_timestamp > earliest 52 | return 53 | end 54 | end 55 | end 56 | 57 | def print_result(arrival_station) 58 | if in_connection[arrival_station] == INF 59 | puts "NO_SOLUTION" 60 | else 61 | route = [] 62 | # We have to rebuild the route from the arrival station 63 | last_connection_index = in_connection[arrival_station] 64 | while last_connection_index != INF 65 | connection = timetable.connections[last_connection_index] 66 | route << connection 67 | last_connection_index = in_connection[connection.departure_station] 68 | end 69 | 70 | # And now print it out in the right direction 71 | route.reverse.each do |c| 72 | puts "#{c.departure_station} #{c.arrival_station} #{c.departure_timestamp} #{c.arrival_timestamp}" 73 | end 74 | end 75 | puts "" 76 | STDOUT.flush 77 | end 78 | 79 | def compute(departure_station, arrival_station, departure_time) 80 | @in_connection = {} 81 | @earliest_arrival = {} 82 | 83 | MAX_STATIONS.times do |i| 84 | in_connection[i] = INF 85 | earliest_arrival[i] = INF 86 | end 87 | 88 | earliest_arrival[departure_station] = departure_time; 89 | 90 | if departure_station <= MAX_STATIONS && arrival_station <= MAX_STATIONS 91 | main_loop(arrival_station) 92 | end 93 | 94 | print_result(arrival_station) 95 | end 96 | end 97 | 98 | def main 99 | csa = CSA.new 100 | 101 | line = STDIN.gets.strip 102 | 103 | while !line.empty? 104 | tokens = line.split(" ") 105 | csa.compute(tokens[0].to_i, tokens[1].to_i, tokens[2].to_i) 106 | line = STDIN.gets.strip 107 | end 108 | end 109 | 110 | main 111 | -------------------------------------------------------------------------------- /csa.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::io::{BufReader,BufRead}; 3 | 4 | const MAX_STATIONS: usize = 100000; 5 | 6 | #[derive(Debug)] 7 | struct Connection { 8 | departure_station: usize, 9 | arrival_station: usize, 10 | departure_timestamp: u32, 11 | arrival_timestamp: u32 12 | } 13 | 14 | impl Connection { 15 | fn parse(line: &str) -> Connection { 16 | let mut splitted = line.split(" ").map(|crumb| { crumb.parse::().unwrap() }); 17 | 18 | Connection { 19 | departure_station: splitted.next().unwrap() as usize, 20 | arrival_station: splitted.next().unwrap() as usize, 21 | departure_timestamp: splitted.next().unwrap(), 22 | arrival_timestamp: splitted.next().unwrap(), 23 | } 24 | } 25 | } 26 | 27 | fn csa_main_loop(timetable: &[Connection], arrival_station: usize, earliest_arrival: &mut [u32], in_connection: &mut [usize]) { 28 | let mut earliest = std::u32::MAX; 29 | 30 | for (i, connection) in timetable.iter().enumerate() { 31 | if connection.departure_timestamp >= earliest_arrival[connection.departure_station] && 32 | connection.arrival_timestamp < earliest_arrival[connection.arrival_station] { 33 | earliest_arrival[connection.arrival_station] = connection.arrival_timestamp; 34 | in_connection[connection.arrival_station] = i; 35 | 36 | if connection.arrival_station == arrival_station && connection.arrival_timestamp < earliest { 37 | earliest = connection.arrival_timestamp; 38 | } 39 | } else if connection.arrival_timestamp > earliest { 40 | break; 41 | } 42 | } 43 | } 44 | 45 | fn csa_print_result(timetable: &Vec, in_connection: &[usize], arrival_station: usize) { 46 | if in_connection[arrival_station] == std::u32::MAX as usize { 47 | println!("NO_SOLUTION"); 48 | } else { 49 | let mut route = Vec::new(); 50 | let mut last_connection_index = in_connection[arrival_station]; 51 | 52 | while last_connection_index != std::u32::MAX as usize { 53 | let ref connection = timetable[last_connection_index]; 54 | route.push(connection); 55 | last_connection_index = in_connection[connection.departure_station]; 56 | } 57 | 58 | for connection in route.iter().rev() { 59 | println!("{} {} {} {}", connection.departure_station, connection.arrival_station, connection.departure_timestamp, connection.arrival_timestamp); 60 | } 61 | } 62 | println!(""); 63 | } 64 | 65 | fn csa_compute(timetable: &Vec, departure_station: usize, arrival_station: usize, departure_time: u32) 66 | { 67 | let mut in_connection = vec!(std::u32::MAX as usize; MAX_STATIONS); 68 | let mut earliest_arrival = vec!(std::u32::MAX; MAX_STATIONS); 69 | 70 | earliest_arrival[departure_station as usize] = departure_time; 71 | 72 | if departure_station < MAX_STATIONS && arrival_station < MAX_STATIONS { 73 | csa_main_loop(&timetable, arrival_station, &mut earliest_arrival, &mut in_connection); 74 | } 75 | 76 | csa_print_result(&timetable, &in_connection, arrival_station); 77 | } 78 | 79 | fn main() { 80 | // Importing connections 81 | let mut buffered_in = BufReader::new(io::stdin()).lines(); 82 | 83 | let timetable = buffered_in.map(|r| { r.ok().expect("failed to read connection line") }) 84 | .take_while(|l| { !l.is_empty() }) 85 | .map(|l| { Connection::parse(l.trim_right()) }) 86 | .collect(); 87 | 88 | // Responding to requests from stdin 89 | 90 | buffered_in = BufReader::new(io::stdin()).lines(); 91 | 92 | buffered_in.map(|r| { r.ok().expect("failed to read connection line") }) 93 | .take_while(|l| { !l.is_empty() }) 94 | .map(|input_line| { 95 | let params = input_line.split(" ") 96 | .map(|crumb| { crumb.parse().ok().expect(&format!("failed to read {} as integer", crumb)) }) 97 | .collect::>(); 98 | 99 | let departure_station = params[0] as usize; 100 | let arrival_station = params[1] as usize; 101 | let departure_time = params[2]; 102 | 103 | csa_compute(&timetable, departure_station, arrival_station, departure_time); 104 | }).collect::>(); 105 | } 106 | -------------------------------------------------------------------------------- /csa.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | typealias Station = Int 4 | 5 | protocol InputType { 6 | func read(count: Int) throws -> [Int]? 7 | } 8 | 9 | struct Error: ErrorType { 10 | let message: String 11 | init(_ message: String) { 12 | self.message = message 13 | } 14 | } 15 | 16 | struct Connection { 17 | let from: Station, to: Station, departure: time_t, arrival: time_t 18 | 19 | init?(input: InputType) throws { 20 | guard let values = try input.read(4) else { return nil } 21 | from = values[0] 22 | to = values[1] 23 | departure = values[2] 24 | arrival = values[3] 25 | guard from >= 0 && to >= 0 else { throw Error("Station number cannot be negative.") } 26 | guard arrival >= departure else { throw Error("Time travel is not supported yet.") } 27 | } 28 | } 29 | 30 | struct Request { 31 | let from: Station, to: Station, departure: time_t 32 | 33 | init?(input: InputType) throws { 34 | guard let values = try input.read(3) else { return nil } 35 | from = values[0] 36 | to = values[1] 37 | departure = values[2] 38 | guard from >= 0 && to >= 0 else { throw Error("Station number cannot be negative.") } 39 | } 40 | } 41 | 42 | struct Router { 43 | private let connections: [Connection] 44 | private let count: Int 45 | 46 | init(input: InputType) throws { 47 | var connections: [Connection] = [] 48 | while let connection = try Connection(input: input) { 49 | connections.append(connection) 50 | } 51 | self.connections = connections 52 | self.count = connections.reduce(0) { (count, connection) in 53 | max(count, connection.from + 1, connection.to + 1) 54 | } 55 | } 56 | 57 | func solve(request: Request) -> [Connection] { 58 | let from = request.from, to = request.to, departure = request.departure 59 | guard count > max(from, to) else { return [] } 60 | var incoming: [Connection?] = Array(count: count, repeatedValue: nil) 61 | for connection in connections { 62 | if connection.departure < departure || connection.to == from { 63 | continue 64 | } 65 | if let final = incoming[to] where connection.departure > final.arrival { 66 | break 67 | } 68 | if let current = incoming[connection.to] where connection.arrival > current.arrival { 69 | continue 70 | } 71 | if connection.from == from { 72 | incoming[connection.to] = connection 73 | } else if let previous = incoming[connection.from] where connection.departure > previous.arrival { 74 | incoming[connection.to] = connection 75 | } 76 | } 77 | var route: [Connection] = [] 78 | var station = to 79 | while let connection = incoming[station] { 80 | route.insert(connection, atIndex: 0) 81 | station = connection.from 82 | } 83 | return route 84 | } 85 | } 86 | 87 | struct TextualInput: InputType { 88 | private let body: () -> String? 89 | 90 | init(_ body: () -> String?) { 91 | self.body = body 92 | } 93 | 94 | func read(count: Int) throws -> [Int]? { 95 | guard let line = body() else { return nil } 96 | guard !line.isEmpty else { return nil } 97 | let components = line.utf8.split(0x20) 98 | guard components.count == count else { throw Error("There should be exactly \(count) values on this line.") } 99 | return try components.map { component in 100 | guard let string = String(component), let integer = Int(string) else { throw Error("\"\(component)\" is not an integer.") } 101 | return integer 102 | } 103 | } 104 | } 105 | 106 | func printRoute(route: S) { 107 | for connection in route { 108 | print("\(connection.from) \(connection.to) \(connection.departure) \(connection.arrival)") 109 | } 110 | print("") 111 | fflush(stdout) 112 | } 113 | 114 | do { 115 | let input = TextualInput({ readLine() }) 116 | let router = try Router(input: input) 117 | while let request = try Request(input: input) { 118 | let route = router.solve(request) 119 | printRoute(route) 120 | } 121 | } catch let error as Error { 122 | fputs("\(error.message)\n", stderr) 123 | exit(1) 124 | } 125 | -------------------------------------------------------------------------------- /csa_golfed.rb: -------------------------------------------------------------------------------- 1 | I=10e5;u=[];u<<$_.split.map(&:to_i)while gets>$/;while gets>$/;d,a,t=$_.split.map &:to_i;j=Hash.new I;e=j.dup;e[d]=t;if d<=I&&a<=I;f=I;i=0;u.map{|m,n,o,p|if e[m]f&&next};end;i=j[a];r=[];while i.flush;end -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | csa_hs: csa.hs makefile 2 | ghc -o csa_hs -Wall -O3 csa.hs && strip csa_hs 3 | 4 | csa_cpp: csa.cc 5 | g++ $(CPPFLAGS) --std=c++11 -O3 -o csa_cpp csa.cc 6 | 7 | csa_go: csa.go 8 | go build -o csa_go csa.go 9 | 10 | csa_c: csa.c 11 | clang -Ofast -o csa_c csa.c 12 | 13 | csa_pascal: csa.pas 14 | fpc csa.pas 15 | 16 | csa_swift: csa.swift 17 | xcrun --sdk macosx swiftc -O -o csa_swift csa.swift 18 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # CSA Challenge 2 | 3 | At Captain Train, we need to compute train routes to find the best combination 4 | with different train operators. 5 | 6 | Our core routing engine is written in C++ and is based on the 7 | Connection Scan Algorithm. 8 | 9 | We had many conversations, both trolls and genuine curiosity how the routing works. 10 | 11 | So we decided a very simple challenge: implement your own routing engine. It is the best 12 | way to learn how the algorithm works and prove that your language is the most expressive, 13 | the most to fun to write code with, the fastest, the safest… 14 | 15 | ## The data 16 | 17 | The timetable is expressed by a collection of tuples (departure station, arrival station, departure timestamp, arrival timestamp). 18 | 19 | The stations are identified by an index. Timestamps are unix timestamp. Do not worry about timezones, validity days etc. We crunched the data before. It is not the most 20 | memory efficient implementation, but it is the easiest (and some argue with the best performance). 21 | 22 | Every tuple is called a *connection*. So the connection (1, 2, 3600, 7200) means that you can take a train from station 1 the 23 | 1st of January 1970 at 1:00 and the following stop of the train will be at 2:00 at the station 2. 24 | 25 | The data will be provided as a space separated values. 26 | 27 | The tuple are ordered by departure timestamp stored in an indexed array. 28 | 29 | ## The algorithm 30 | 31 | The CSA is very simple. For every station `s` we keep the best arrival time and arrival connection. We call those two connections 32 | `arrival_timestamp[s]` and `in_connection[s]`. 33 | 34 | We want to go from `o` to `d` leaving at the timestamp `t0` 35 | 36 | ### Initialisation 37 | 38 | ``` 39 | For each station s 40 | arrival_timestamp[s] = infinite 41 | in_connection[s] = invalid_value 42 | 43 | arrival_timestamp[o] = t0 44 | ``` 45 | 46 | ### Main loop 47 | 48 | We iterate over all the connections to see if we can improve any connection. 49 | 50 | Once we have explored all connections, we have computed all the earliest arrival routes from `o` to any other station. 51 | 52 | ``` 53 | For each connection c 54 | if arrival_timestamp[c.departure_station] < c.departure_timestamp and arrival_timestamp[c.arrival_station] > c.arrival_timestamp 55 | arrival_timestamp[c.arrival_station] ← c.arrival_timestamp 56 | in_connection[c.arrival_station] = c 57 | ``` 58 | 59 | ### Getting the actual path back 60 | 61 | We just need to go from `d` and look up all the in_connections until we reach `o` and we have the path and the timetable. 62 | 63 | ### Immediate optimizations 64 | 65 | There is no need to look all the connections. We start with the first having `c.departure_timestamp >= t0` and we stop 66 | as soon as `c.departure_timestamp > arrival_timestamp`. 67 | 68 | ## Limitations 69 | 70 | While this algorithm find routes, there are the following limitations to be aware of: 71 | 72 | * it computes the earliest arrival. However, a better solution might leaver later and arrive at the same time 73 | * the route with the least connections will not be computed 74 | * no connection time is considered: you might have to run to get the next train 75 | * multiple stations in a City like Paris are not considered 76 | 77 | ## Input/output 78 | 79 | Your program should read from the standard input. 80 | 81 | The timetable is given one connection per line, each value of the tuple is space separated. 82 | 83 | An empty line indicates that the input is done. The following lines are a route request with three values separated by spaces: 84 | `departure_station arrival_station departure_timestamp`. A new line indicates that the program should stop. 85 | 86 | Here is a example of input 87 | 88 | ``` 89 | 1 2 3600 7200 90 | 2 3 7800 9000 91 | 92 | 1 3 3000 93 | 94 | ``` 95 | 96 | The output should be a line for each connection on the standart output. An empty line indicates the end of the output. Hence the answer shall be 97 | 98 | ``` 99 | 1 2 3600 7200 100 | 2 3 7800 9000 101 | 102 | ``` 103 | 104 | ## Reference implementation 105 | 106 | An implementation in C++11 is available. 107 | 108 | It can be compiled with ```g++ $CPPFLAGS --std=c++11 -O3 -o csa_cpp csa.cc``` 109 | 110 | Run the test with ```ruby test.rb ./csa_cpp``` 111 | 112 | ## Haskell implementation 113 | 114 | Debian packages: 115 | - haskell 116 | - bin-utils 117 | 118 | Build: ```ghc -o csa_hs -Wall -O3 csa.hs && strip csa_hs``` 119 | 120 | Run the test with ```ruby test.rb ./csa_hs``` 121 | 122 | ## Java implementation 123 | 124 | Build: ```javac CSA.java``` 125 | 126 | Run the test with ```ruby test.rb "java CSA"``` 127 | 128 | ## Lua implementation 129 | 130 | Run the test with ```ruby test.rb "luajit csa.lua"``` 131 | 132 | ## Rust implementation 133 | 134 | Build: ```cargo build --release``` 135 | 136 | Run the test with ```ruby test.rb ./target/release/csa_rs``` 137 | 138 | ## Challenge 139 | 140 | Try to write: 141 | 142 | * The first implementation passing the tests 143 | * Smallest source code (measured in bytes). Any library installable without an external repository on Debian, Ubuntu, Archlinux is accepted 144 | * Smallest executable (same rule considering dependencies) 145 | * The most unreadable 146 | * The least alphanumerical characters 147 | * The most creative implementation of the algorithm 148 | 149 | ## Benchmarking 150 | 151 | We included 48 hours of train connections in Europe starting the January 1st 1970. 152 | The data is not real, but pretty close. 153 | 154 | You can run the benchmark with ```ruby bench.rb ./csa_cpp``` 155 | -------------------------------------------------------------------------------- /stations: -------------------------------------------------------------------------------- 1 | 2121 2 | 2125 3 | 2141 4 | 2142 5 | 2146 6 | 2174 7 | 2311 8 | 2314 9 | 2315 10 | 2318 11 | 2324 12 | 2328 13 | 2346 14 | 2347 15 | 2348 16 | 2349 17 | 2350 18 | 2353 19 | 2354 20 | 2356 21 | 2357 22 | 2358 23 | 2361 24 | 2364 25 | 2367 26 | 2369 27 | 2382 28 | 2383 29 | 2384 30 | 2386 31 | 2387 32 | 2388 33 | 2620 34 | 2667 35 | 2668 36 | 2682 37 | 2700 38 | 2708 39 | 2759 40 | 2762 41 | 2772 42 | 2907 43 | 2908 44 | 2913 45 | 2933 46 | 2934 47 | 2977 48 | 2981 49 | 2985 50 | 2990 51 | 2996 52 | 3005 53 | 3013 54 | 3015 55 | 3023 56 | 3043 57 | 3048 58 | 3067 59 | 3071 60 | 3110 61 | 3121 62 | 3124 63 | 3131 64 | 3132 65 | 3134 66 | 3135 67 | 3136 68 | 3138 69 | 3139 70 | 3140 71 | 3141 72 | 3142 73 | 3144 74 | 3145 75 | 3146 76 | 3155 77 | 3156 78 | 3157 79 | 3158 80 | 3159 81 | 3160 82 | 3161 83 | 3162 84 | 3163 85 | 3164 86 | 3165 87 | 3166 88 | 3167 89 | 3168 90 | 3169 91 | 3173 92 | 3175 93 | 3263 94 | 3264 95 | 3265 96 | 3266 97 | 3267 98 | 3268 99 | 3289 100 | 3292 101 | 3293 102 | 3294 103 | 3295 104 | 3296 105 | 3297 106 | 3400 107 | 3437 108 | 3453 109 | 3454 110 | 3513 111 | 3519 112 | 3528 113 | 3540 114 | 3541 115 | 3542 116 | 3625 117 | 3649 118 | 3763 119 | 3765 120 | 3767 121 | 3768 122 | 3777 123 | 3920 124 | 3922 125 | 3928 126 | 3931 127 | 3938 128 | 3939 129 | 3940 130 | 3941 131 | 3942 132 | 3943 133 | 3975 134 | 4107 135 | 4235 136 | 4258 137 | 4262 138 | 4270 139 | 4419 140 | 7378 141 | 7438 142 | 8414 143 | 9249 144 | 9379 145 | 9727 146 | 9736 147 | 9750 148 | 9980 149 | 10312 150 | 12378 151 | 12390 152 | 12396 153 | 12400 154 | 13111 155 | 14690 156 | 14763 157 | 14805 158 | 14827 159 | 14828 160 | 14832 161 | 14862 162 | 14931 163 | 14939 164 | 14970 165 | 15005 166 | 15038 167 | 15039 168 | 15050 169 | 15051 170 | 15122 171 | 15126 172 | 15180 173 | 16359 174 | 16360 175 | 16361 176 | 16362 177 | 16363 178 | 16364 179 | 16365 180 | 16366 181 | 16367 182 | 16368 183 | 16369 184 | 16383 185 | 16384 186 | 16386 187 | 16387 188 | 16388 189 | 16389 190 | 16393 191 | 16394 192 | 16395 193 | 16396 194 | 16397 195 | 16402 196 | 16403 197 | 16404 198 | 16405 199 | 16406 200 | 16407 201 | 16408 202 | 16409 203 | 16410 204 | 16411 205 | 16412 206 | 16413 207 | 16427 208 | 16470 209 | 16471 210 | 16472 211 | 16473 212 | 16474 213 | 16475 214 | 16476 215 | 16477 216 | 16479 217 | 16481 218 | 16483 219 | 16486 220 | 16488 221 | 16511 222 | 16517 223 | 16528 224 | 16531 225 | 16573 226 | 16588 227 | 16608 228 | 16648 229 | 16649 230 | 16660 231 | 16673 232 | 16677 233 | 16710 234 | 16715 235 | 16730 236 | 16764 237 | 16765 238 | 16766 239 | 16767 240 | 16768 241 | 16769 242 | 16770 243 | 16771 244 | 16772 245 | 16773 246 | 16774 247 | 16775 248 | 16776 249 | 16778 250 | 16779 251 | 16780 252 | 16781 253 | 16782 254 | 16783 255 | 16786 256 | 16787 257 | 16788 258 | 16790 259 | 16791 260 | 16793 261 | 16794 262 | 16797 263 | 16799 264 | 16802 265 | 16819 266 | 16827 267 | 16828 268 | 16829 269 | 16830 270 | 16831 271 | 16877 272 | 16882 273 | 16883 274 | 16884 275 | 16886 276 | 16887 277 | 16888 278 | 16889 279 | 16890 280 | 16894 281 | 16895 282 | 16896 283 | 16899 284 | 16900 285 | 16901 286 | 16902 287 | 16903 288 | 16912 289 | 16932 290 | 16933 291 | 16934 292 | 16955 293 | 16966 294 | 16967 295 | 16971 296 | 16991 297 | 16994 298 | 16995 299 | 17119 300 | 17179 301 | 17226 302 | 17295 303 | 17296 304 | 17298 305 | 17299 306 | 17306 307 | 17310 308 | 17434 309 | 17465 310 | 17505 311 | 17540 312 | 17542 313 | 17543 314 | 17544 315 | 17545 316 | 17555 317 | 17558 318 | 17559 319 | 17561 320 | 17562 321 | 17563 322 | 17567 323 | 17568 324 | 17569 325 | 17570 326 | 17573 327 | 17574 328 | 17575 329 | 17576 330 | 17577 331 | 17578 332 | 17579 333 | 17580 334 | 17581 335 | 17582 336 | 17583 337 | 17585 338 | 17586 339 | 17587 340 | 17588 341 | 17589 342 | 17590 343 | 17591 344 | 17592 345 | 17593 346 | 17594 347 | 17595 348 | 17596 349 | 17597 350 | 17599 351 | 17600 352 | 17601 353 | 17602 354 | 17603 355 | 17604 356 | 17605 357 | 17611 358 | 17613 359 | 17615 360 | 17636 361 | 17638 362 | 17663 363 | 17664 364 | 17666 365 | 17667 366 | 17674 367 | 17703 368 | 17704 369 | 17707 370 | 17717 371 | 17719 372 | 17722 373 | 17763 374 | 17778 375 | 17785 376 | 17810 377 | 17822 378 | 17837 379 | 17838 380 | 17840 381 | 17844 382 | 17849 383 | 17850 384 | 17851 385 | 17854 386 | 17857 387 | 17858 388 | 17859 389 | 17860 390 | 17861 391 | 17862 392 | 17874 393 | 17893 394 | 17897 395 | 17900 396 | 17904 397 | 17906 398 | 17909 399 | 17925 400 | 17926 401 | 17928 402 | 17931 403 | 17932 404 | 17933 405 | 17934 406 | 17935 407 | 17936 408 | 17937 409 | 17938 410 | 17960 411 | 17961 412 | 17967 413 | 17976 414 | 17978 415 | 17979 416 | 17982 417 | 17983 418 | 17986 419 | 17989 420 | 17990 421 | 17991 422 | 17995 423 | 17996 424 | 18010 425 | 18011 426 | 18013 427 | 18014 428 | 18023 429 | 18026 430 | 18043 431 | 18044 432 | 18085 433 | 18086 434 | 18087 435 | 18088 436 | 18101 437 | 18124 438 | 18149 439 | 18160 440 | 18239 441 | 18240 442 | 18242 443 | 18295 444 | 18310 445 | 18372 446 | 18475 447 | 18493 448 | 18495 449 | 18500 450 | 18575 451 | 18578 452 | 18579 453 | 18595 454 | 18596 455 | 18597 456 | 18598 457 | 18600 458 | 18601 459 | 18605 460 | 18610 461 | 18613 462 | 18648 463 | 18652 464 | 18653 465 | 18654 466 | 18659 467 | 18664 468 | 18705 469 | 18706 470 | 18736 471 | 18756 472 | 18783 473 | 18897 474 | 18911 475 | 18915 476 | 18926 477 | 18927 478 | 18931 479 | 18943 480 | 18944 481 | 18945 482 | 18952 483 | 18953 484 | 18954 485 | 18955 486 | 18956 487 | 18958 488 | 18964 489 | 18965 490 | 18966 491 | 18967 492 | 18970 493 | 18974 494 | 18996 495 | 19000 496 | 19003 497 | 19004 498 | 19005 499 | 19006 500 | 19009 501 | 19011 502 | 19013 503 | 19015 504 | 19016 505 | 19024 506 | 19047 507 | 19049 508 | 19050 509 | 19052 510 | 19055 511 | 19056 512 | 19063 513 | 19064 514 | 19066 515 | 19070 516 | 19071 517 | 19072 518 | 19073 519 | 19083 520 | 19084 521 | 19101 522 | 19102 523 | 19104 524 | 19106 525 | 19117 526 | 19124 527 | 19137 528 | 19139 529 | 19142 530 | 19251 531 | 19252 532 | 19259 533 | 19404 534 | 19405 535 | 19434 536 | 19467 537 | 19468 538 | 19484 539 | 19485 540 | 19486 541 | 19487 542 | 19488 543 | 19499 544 | 19561 545 | 19562 546 | 19564 547 | 19565 548 | 19566 549 | 19567 550 | 19665 551 | 19676 552 | 19740 553 | 19751 554 | 19752 555 | 19764 556 | 19790 557 | 19800 558 | 19818 559 | 19819 560 | 19820 561 | 19821 562 | 19822 563 | 19823 564 | 19824 565 | 19825 566 | 19826 567 | 19834 568 | 19835 569 | 19836 570 | 19837 571 | 19839 572 | 19840 573 | 19841 574 | 19842 575 | 19843 576 | 19844 577 | 19860 578 | 19862 579 | 19866 580 | 19867 581 | 19868 582 | 19869 583 | 19870 584 | 19887 585 | 19897 586 | 19904 587 | 19905 588 | 19906 589 | 19907 590 | 19908 591 | 19909 592 | 19913 593 | 19914 594 | 19915 595 | 19916 596 | 19919 597 | 19934 598 | 19977 599 | 19978 600 | 19979 601 | 19980 602 | 19981 603 | 19982 604 | 19983 605 | 19984 606 | 19985 607 | 20004 608 | 20005 609 | 20006 610 | 20007 611 | 20008 612 | 20009 613 | 20010 614 | 20011 615 | 20012 616 | 20015 617 | 20018 618 | 20027 619 | 20037 620 | 20052 621 | 20054 622 | 20227 623 | 20228 624 | 20239 625 | 20241 626 | 20244 627 | 20254 628 | 20261 629 | 20318 630 | 20319 631 | 20405 632 | 20428 633 | 20431 634 | 20432 635 | 20433 636 | 20488 637 | 20493 638 | 20522 639 | 20576 640 | 20583 641 | 20598 642 | 20599 643 | 20641 644 | 20644 645 | 20646 646 | 20655 647 | 20676 648 | 20677 649 | 20678 650 | 20679 651 | 20681 652 | 20682 653 | 20683 654 | 20719 655 | 20720 656 | 20732 657 | 20733 658 | 20773 659 | 20803 660 | 20806 661 | 20807 662 | 20908 663 | 20909 664 | 20910 665 | 20911 666 | 20912 667 | 20914 668 | 20915 669 | 20916 670 | 20991 671 | 21065 672 | 21089 673 | 21093 674 | 21199 675 | 21345 676 | 21413 677 | 21419 678 | 21472 679 | 21565 680 | 21568 681 | 21569 682 | 21573 683 | 21574 684 | 21575 685 | 21578 686 | 21579 687 | 21580 688 | 21584 689 | 21588 690 | 21607 691 | 21614 692 | 21619 693 | 21625 694 | 21680 695 | 21735 696 | 21737 697 | 21738 698 | 21739 699 | 21740 700 | 21742 701 | 21744 702 | 21749 703 | 21809 704 | 21810 705 | 21811 706 | 21812 707 | 21866 708 | 21924 709 | 21959 710 | 21966 711 | 21969 712 | 21970 713 | 21972 714 | 21973 715 | 21974 716 | 21979 717 | 21983 718 | 21993 719 | 21995 720 | 21996 721 | 21999 722 | 22001 723 | 22002 724 | 22003 725 | 22004 726 | 22005 727 | 22006 728 | 22007 729 | 22008 730 | 22010 731 | 22011 732 | 22013 733 | 22014 734 | 22015 735 | 22034 736 | 22035 737 | 22036 738 | 22037 739 | 22090 740 | 22130 741 | 22490 742 | 22626 743 | 22627 744 | 22640 745 | 22654 746 | 22682 747 | 22706 748 | 22707 749 | 22725 750 | 22748 751 | 22749 752 | 22750 753 | 22786 754 | 22801 755 | 22802 756 | 22803 757 | 22889 758 | 22895 759 | 22896 760 | 22937 761 | 22946 762 | 22947 763 | 22950 764 | 22954 765 | 22956 766 | 22957 767 | 22959 768 | 22960 769 | 22967 770 | 23038 771 | 23052 772 | 23059 773 | 23126 774 | 23150 775 | 23175 776 | 23207 777 | 23273 778 | 23999 779 | 24532 780 | 24884 781 | 25098 782 | 25220 783 | 25258 784 | 25260 785 | 25312 786 | 25530 787 | 25836 788 | 25877 789 | 25878 790 | 25879 791 | 25880 792 | 26733 793 | 26734 794 | 26735 795 | 26738 796 | 26739 797 | 26740 798 | 26741 799 | 26742 800 | 26743 801 | 26744 802 | 26745 803 | 26746 804 | 26750 805 | 26753 806 | 26755 807 | 26756 808 | 26757 809 | 26758 810 | 26759 811 | 26768 812 | 26782 813 | 26789 814 | 26791 815 | 26797 816 | 26799 817 | 26804 818 | 26813 819 | 26815 820 | 26823 821 | 26827 822 | 26830 823 | 26850 824 | 26865 825 | 26866 826 | 26876 827 | 26877 828 | 26878 829 | 26888 830 | 26889 831 | 26891 832 | 26892 833 | 26894 834 | 26900 835 | 26902 836 | 26904 837 | 26906 838 | 26914 839 | 26939 840 | 26946 841 | 26947 842 | 26974 843 | 26976 844 | 26986 845 | 27006 846 | 27016 847 | 27019 848 | 27021 849 | 27022 850 | 27033 851 | 27035 852 | 27038 853 | 27040 854 | 27045 855 | 27058 856 | 27070 857 | 27071 858 | 27078 859 | 27103 860 | 27104 861 | 27113 862 | 27122 863 | 27134 864 | 27140 865 | 27145 866 | 27275 867 | 27403 868 | 27404 869 | 27669 870 | 27673 871 | 27713 872 | 27715 873 | 27766 874 | 27767 875 | 27768 876 | 27770 877 | 27777 878 | 27778 879 | 27826 880 | 27838 881 | 27840 882 | 27856 883 | 27863 884 | 27917 885 | 27956 886 | 27965 887 | 28115 888 | 28187 889 | 28191 890 | 28237 891 | 28306 892 | 28435 893 | 28445 894 | 28513 895 | 28552 896 | 28607 897 | 28620 898 | 28867 899 | 28887 900 | 29368 901 | 29371 902 | 29372 903 | 29374 904 | 29377 905 | 29431 906 | 29432 907 | 29433 908 | 29480 909 | 29481 910 | 29492 911 | 29493 912 | 29503 913 | 29504 914 | 29519 915 | 29520 916 | 29521 917 | 29522 918 | 29525 919 | 29530 920 | 29531 921 | 29532 922 | 29533 923 | 29534 924 | 29539 925 | 29540 926 | 29541 927 | 29542 928 | 29543 929 | 29544 930 | 29545 931 | 29546 932 | 29547 933 | 29551 934 | 29557 935 | 29558 936 | 29559 937 | 29560 938 | 29561 939 | 29562 940 | 29582 941 | 29605 942 | 29612 943 | 29613 944 | 29614 945 | 29615 946 | 29616 947 | 29617 948 | 29618 949 | 29619 950 | 29620 951 | 29621 952 | 29622 953 | 29629 954 | 29630 955 | 29631 956 | 29632 957 | 29634 958 | 29638 959 | 29656 960 | 29657 961 | 29658 962 | 29659 963 | 29904 964 | 29911 965 | 30095 966 | 30560 967 | 30563 968 | 30593 969 | 30694 970 | 30891 971 | 30912 972 | 30939 973 | 30948 974 | 31053 975 | 31079 976 | 31081 977 | 31082 978 | 31090 979 | 31120 980 | 31194 981 | 31254 982 | 31446 983 | 31447 984 | 31627 985 | 31638 986 | 31652 987 | 31726 988 | 31923 989 | 32441 990 | 32628 991 | 32678 992 | 32950 993 | 33094 994 | 34208 995 | 34218 996 | 34219 997 | 34221 998 | 34274 999 | 34368 1000 | 34541 1001 | 34829 1002 | 35038 1003 | 35083 1004 | 35084 1005 | 35093 1006 | 35123 1007 | 35126 1008 | 35130 1009 | 35285 1010 | 35305 1011 | 35318 1012 | 35335 1013 | 35338 1014 | 35350 1015 | 35363 1016 | 35364 1017 | 35369 1018 | 35398 1019 | 35451 1020 | 35466 1021 | 35547 1022 | 35715 1023 | 35733 1024 | 35781 1025 | 35815 1026 | 35821 1027 | 36975 1028 | 36989 1029 | 36990 1030 | 36992 1031 | 36997 1032 | 37001 1033 | 37005 1034 | 37007 1035 | 37008 1036 | 37023 1037 | 37024 1038 | 37027 1039 | 37028 1040 | 37029 1041 | 37033 1042 | 37034 1043 | 37036 1044 | 37037 1045 | 37038 1046 | 37039 1047 | 37043 1048 | 37051 1049 | 37054 1050 | 37057 1051 | 37060 1052 | 37065 1053 | 37066 1054 | 37068 1055 | 37069 1056 | 37070 1057 | 37071 1058 | 37077 1059 | 37079 1060 | 37080 1061 | 37081 1062 | 37082 1063 | 37086 1064 | 37087 1065 | 37096 1066 | 37132 1067 | 37736 1068 | -------------------------------------------------------------------------------- /test.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'test/unit' 4 | 5 | if ARGV.size != 1 6 | puts "Usage: ruby #{$0} routing_executable" 7 | exit(-1) 8 | end 9 | 10 | EXECUTABLE = ARGV[0] 11 | 12 | class TestCSA < Test::Unit::TestCase 13 | 14 | TIMETABLE =< tokens[0].to_i, 42 | :arrival_station => tokens[1].to_i, 43 | :departure_timestamp => tokens[2].to_i, 44 | :arrival_timestamp => tokens[3].to_i, 45 | } 46 | 47 | line = io.gets.strip 48 | end 49 | end 50 | 51 | result 52 | end 53 | 54 | def test_simple_route 55 | @io.puts "1 2 3000" 56 | response = read_answer @io 57 | assert_equal 1, response.size 58 | assert_equal 1, response[0][:departure_station] 59 | assert_equal 2, response[0][:arrival_station] 60 | assert_equal 3600, response[0][:departure_timestamp] 61 | assert_equal 7200, response[0][:arrival_timestamp] 62 | end 63 | 64 | def test_route_with_connection 65 | @io.puts "1 3 3000" 66 | response = read_answer @io 67 | assert_equal 2, response.size 68 | assert_equal 1, response[0][:departure_station] 69 | assert_equal 2, response[0][:arrival_station] 70 | assert_equal 7200, response[0][:arrival_timestamp] 71 | assert_equal 2, response[1][:departure_station] 72 | assert_equal 3, response[1][:arrival_station] 73 | assert_equal 9000, response[1][:arrival_timestamp] 74 | end 75 | 76 | def test_later_departure 77 | @io.puts "1 3 4000" 78 | response = read_answer @io 79 | assert_equal 1, response.size 80 | assert_equal 1, response[0][:departure_station] 81 | assert_equal 3, response[0][:arrival_station] 82 | assert_equal 10000, response[0][:arrival_timestamp] 83 | end 84 | 85 | def test_invalid_station 86 | @io.puts "5 3 4000" 87 | response = read_answer @io 88 | assert_equal 0, response.size 89 | end 90 | 91 | def test_multiple_queries 92 | @io.puts "1 3 4000" 93 | response1 = read_answer @io 94 | @io.puts "1 3 4000" 95 | response2 = read_answer @io 96 | 97 | assert_equal 1, response1.size 98 | assert_equal 1, response2.size 99 | end 100 | 101 | end 102 | --------------------------------------------------------------------------------