Google code jam 2008 QR - Train Timetable

这是Google code jam 2008 QR的第二道题,关于行驶在两站之间的列车时间表规划的问题。算法不难,可以用贪心法,但是由于每一步只需要取最大或最小值,因此提出了用STL的heap(最大堆最小堆)的数据结构进行存储。程序涉及到操作符的重载等(当然这样表示Time比较麻烦,应直接计算为整型,这里权当是练手吧)。最后给出源码。


A train line has two stations on it, A and B. Trains can take trips from A to B or from B to A multiple times during a day. When a train arrives at B from A (or arrives at A from B), it needs a certain amount of time before it is ready to take the return journey - this is the turnaround time. For example, if a train arrives at 12:00 and the turnaround time is 0 minutes, it can leave immediately, at 12:00.

A train timetable specifies departure and arrival time of all trips between A and B. The train company needs to know how many trains have to start the day at A and B in order to make the timetable work: whenever a train is supposed to leave A or B, there must actually be one there ready to go. There are passing sections on the track, so trains don't necessarily arrive in the same order that they leave. Trains may not travel on trips that do not appear on the schedule.



The first line of input gives the number of cases, N. N test cases follow.


Each case contains a number of lines. The first line is the turnaround time, T, in minutes. The next line has two numbers on it, NA and NB. NA is the number of trips from A to B, and NB is the number of trips from B to A. Then there are NA lines giving the details of the trips from A to B.


Each line contains two fields, giving the HH:MM departure and arrival time for that trip. The departure time for each trip will be earlier than the arrival time. All arrivals and departures occur on the same day. The trips may appear in any order - they are not necessarily sorted by time. The hour and minute values are both two digits, zero-padded, and are on a 24-hour clock (00:00 through 23:59).


After these NA lines, there are NB lines giving the departure and arrival times for the trips from B to A.


For each test case, output one line containing "Case #x: " followed by the number of trains that must start at A and the number of trains that must start at B.



1 ≤ N ≤ 100

Small dataset

0 ≤ NA, NB ≤ 20

0 ≤ T ≤ 5

Large dataset

0 ≤ NA, NB ≤ 100

0 ≤ T ≤ 60



3 2
09:00 12:00
10:00 13:00
11:00 12:30
12:02 15:00
09:00 10:30
2 0
09:00 09:01
12:00 12:02

Case #1: 2 2
Case #2: 2 0


This problem can be solved with a greedy strategy. The simplest way to do this is by scanning through a list of all the trips, sorted by departure time, and keeping track of the set of trains that will be available at each station, and when they will be ready to take a trip.

When we examine a trip, we see if there will be a train ready at the departure station by the departure time. If there is, then we remove that train from the list of available trains. If there is not, then our solution will need one new train added for the departure station. Then we compute when the train taking this trip will be ready at the other station for another trip, and add this train to the set of available trains at the other station. If a train leaves station A at 12:00 and arrives at station B at 13:00, with a 5-minute turnaround time, it will be available for a return journey from B to A at 13:05.

We need to be able to efficiently identify the earliest a train can leave from a station; and update this set of available trains by adding new trains or removing the earliest train. This can be done using a heap data structure for each station.

Sample Python code provided below that solves a test case for this problem:

def SolveCase(case_index, case):
  T, (tripsa, tripsb) = case
  trips = []
  for trip in tripsa:
    trips.append([trip[0], trip[1], 0])
  for trip in tripsb:
    trips.append([trip[0], trip[1], 1])


  start = [0, 0]
  trains = [[], []]

  for trip in trips:
    d = trip[2]
    if trains[d] and trains[d][0] <= trip[0]:
      # We're using the earliest train available, and
      # we have to delete it from this station's trains.
      # No train was available for the current trip,
      # so we're adding one.
      start[d] += 1
    # We add an available train in the arriving station at the
    # time of arrival plus the turnaround time.
    heappush(trains[1 - d], trip[1] + T)

  print "Case #%d: %d %d" % (case_index, start[0], start[1])
Luckily Python has methods that implement the heap data structure operations. This solution takes O(n log n) time, where n is the total number of trips, because at each trip we do at most one insert or one delete operation from the heaps, and heap operations take O(log n) time.

Source Code in C++
  1#include <hash_set>
  2#include <iostream>
  4using namespace std;
  6#define Rep(i,n) for (int i(0),_n(n); i<_n; ++i)
  8struct Time
 10    int HH;
 11    int MM;
 12    void Add(int deltaMM, int deltaHH=0)
 13    {
 14        MM += deltaMM;
 15        if(MM>=60{
 16            MM%=60;
 17            deltaHH++;
 18        }

 19        HH += deltaHH;
 20        if(HH>=24{
 21            HH%=24;
 22        }

 23    }

 24    bool operator< (const Time& B) const
 25    {
 26        if(HH<B.HH)
 27            return true;
 28        else if(HH==B.HH) {
 29            if(MM<B.MM)
 30                return true;
 31            else
 32                return false;
 33        }
 34            return false;
 35    }

 36    bool operator> (const Time& B) const
 37    {
 38        if(HH>B.HH)
 39            return true;
 40        else if(HH==B.HH) {
 41            if(MM>B.MM)
 42                return true;
 43            else
 44                return false;
 45        }
 46            return false;
 47    }

 48    bool operator<= (const Time& B) const
 49    {
 50        return !(*this>B);
 51    }

 54struct Trip
 56    Time departure;
 57    Time arrive;
 58    char station; //0:A;1:B
 59    Trip()
 60    {
 61    }

 62    Trip(char pos)
 63    {
 64        station = pos;
 65    }

 66    bool operator< (const Trip& B) const
 67    {
 68        if(arrive<B.arrive)
 69            return true;
 70        else
 71            return false;
 72    }

 75int main()
 77    int T;
 78    freopen("..\\","r",stdin);
 79    freopen("..\\s.out","w",stdout);
 80    scanf("%d"&T);
 81    Rep(t, T) {
 82        int turnTime;
 83        scanf("%d"&turnTime);
 84        int NA, NB;
 85        scanf("%d%d"&NA, &NB);
 86        vector<Trip> trips;
 87        vector<Time> trains[2];
 88        trips.reserve(NA+NB);
 89        Rep(i, NA) {
 90            Trip trip(0);
 91            scanf("%d:%d %d:%d"&trip.departure.HH, &trip.departure.MM, &trip.arrive.HH, &trip.arrive.MM);
 92            trips.push_back(trip);
 93        }

 94        Rep(i, NB) {
 95            Trip trip(1);
 96            scanf("%d:%d %d:%d"&trip.departure.HH, &trip.departure.MM, &trip.arrive.HH, &trip.arrive.MM);
 97            trips.push_back(trip);
 98        }

 99        sort(trips.begin(), trips.end());
101        int start[2= {0};
102        Rep(i, NA+NB) {
103            int d = trips[i].station;
104            if(!trains[d].empty() && trains[d][0<= trips[i].departure) {
105                pop_heap(trains[d].begin(),trains[d].end(),greater<Time>());
106                trains[d].pop_back();
107            }
 else {
108                start[d]++;
109            }

110            Time train(trips[i].arrive);
111            train.Add(turnTime);
112            trains[1-d].push_back(train);
113            push_heap(trains[1-d].begin(),trains[1-d].end(),greater<Time>());
114        }

116        printf("Case #%d: %d %d\n", t+1, start[0], start[1]);
117    }

118    return 0;


posted on 2009-08-13 14:09  CLive Studio  阅读(...)  评论(...编辑  收藏