#include #include #include #include #include #include #include using namespace std; bool debugging = false; #define CERR(x) if (debugging) cerr << " " << x; const int hoursToSeconds = 60*60; const int secondsPerDay = 24 * hoursToSeconds; /** This program is structured as a discrete-event simulation. A priority queue of events,c ordered by time, is used to drive the simulation. Events include sunrise, sunset, docks becoming (un)available due to tides, the canoeist arriving at docks, etc. */ struct Simulation; class Event { public: int time; Event (int t): time(t) {} // "Do" the event virtual void doIt (Simulation&) = 0; }; class OrderedEvent { public: Event* event; OrderedEvent(Event* e): event(e) {} bool operator<(OrderedEvent other) const { return event->time > other.event->time; } bool operator>(OrderedEvent other) const { return event->time < other.event->time; } }; struct Simulation { // Startup information int sunRise0, sunSet0; int sunRiseDelta, sunSetDelta; int lowTide0, lowTideDelta; double speed; int maxdays; int nDocks; double* dockLocations; int* dockTideInterval; // Dock descriptions bool* dockIsAccessible; vector* docked; vector* offshore; // Current status bool sunIsUp; int lastDockReached; int time; int nextSunset; int day() {return time / secondsPerDay;} // event queue priority_queue events; Simulation (istream& in, int maxDays); void run(); void report(); void debug(ostream&); void scheduleArrivalsFrom (int dock); }; int readTime (istream& in) { int h, m, s; char c; in >> h >> c >> m >> c >> s; int sign = 1; if (h < 0) { sign = -1; h = -h; } return sign * (s + 60 * (m + 60*h)); } string formattedTime (int time) { int d, h, m, s; d = time / secondsPerDay; time = time % secondsPerDay; h = time / hoursToSeconds; time = time % hoursToSeconds; m = time / 60; s = time % 60; ostringstream out; out << d << ' ' << h << ':' << m << ':' << s; return out.str(); } ///////////////////// class Arrival: public Event { int dock; vector dailyStops; public: Arrival (int time, int dockNum, const vector& stops) : Event(time), dock(dockNum), dailyStops(stops) {} virtual void doIt (Simulation& sim); }; void Arrival::doIt (Simulation& sim) { if (sim.sunIsUp && sim.docked[dock].size() == 0) { // If dock is accessible, record that we could put in there. Else // just note that we have arrived. if (sim.dockIsAccessible[dock]) { sim.docked[dock] = dailyStops; sim.offshore[dock].clear(); sim.lastDockReached = (dock > sim.lastDockReached) ? dock : sim.lastDockReached; } else { if (sim.offshore[dock].size() == 0 || dailyStops.size() < sim.offshore[dock].size()) sim.offshore[dock] = dailyStops; } } CERR("Arrival at dock " << dock << "\t"); sim.debug(cerr); } void Simulation::scheduleArrivalsFrom (int dock) { if (dockIsAccessible[dock]) for (int nextDock = dock+1; nextDock <= nDocks; ++nextDock) if (docked[nextDock].size() == 0) { int nextArrival = time + (int)((dockLocations[nextDock] - dockLocations[dock]) / speed); if (nextArrival <= nextSunset) events.push(OrderedEvent (new Arrival(nextArrival, nextDock, docked[dock]))); } } ///////////////////// class SunRise: public Event { public: SunRise (int time): Event(time) {} virtual void doIt (Simulation& sim); }; void SunRise::doIt (Simulation& sim) { // schedule next sunrise sim.events.push(OrderedEvent(new SunRise(sim.time+sim.sunRiseDelta))); // Canoe may be at any dock that we have been able to put in at. // Schedule arrivals from each such dock to all subsequent // docks that can be reached before sunrise. sim.sunIsUp = true; for (int d = 0; d < sim.nDocks; ++d) if (sim.dockIsAccessible[d]) if (sim.docked[d].size() > 0) sim.scheduleArrivalsFrom(d); fill_n (sim.offshore, sim.nDocks+1, vector()); CERR("Sunrise\t"); sim.debug(cerr); } ///////////////////// class SunSet: public Event { public: SunSet (int time): Event(time) {} virtual void doIt (Simulation& sim); }; void SunSet::doIt (Simulation& sim) { sim.sunIsUp = false; // schedule next sunset sim.events.push(OrderedEvent(new SunSet(sim.time+sim.sunSetDelta))); sim.nextSunset = sim.time+sim.sunSetDelta; // Eliminate any offshore canoes fill_n (sim.offshore, sim.nDocks+1, vector()); // Mark all docks where we have put in for the night as places where // we have stopped at the end of this day. for (int d = 0; d <= sim.nDocks; ++d) if (sim.docked[d].size() > 0) // && // sim.docked[d].back() != d) { sim.docked[d].push_back(d); if (debugging) { cerr << "dock " << d << " trace: "; for (int i = 0; i < sim.docked[d].size(); ++i) cerr << sim.docked[d][i] << " "; cerr << endl; } } CERR("Sunset\t"); sim.debug(cerr); } ///////////////////// class TideIsLow: public Event { int dock; public: TideIsLow (int time, int dockNumber): Event(time), dock(dockNumber) {} virtual void doIt (Simulation& sim); }; void TideIsLow::doIt (Simulation& sim) { sim.dockIsAccessible[dock] = false; // schedule next low tide sim.events.push(OrderedEvent(new TideIsLow(sim.time+sim.lowTideDelta, dock))); CERR("Low tide at dock " << dock << "\t"); sim.debug(cerr); } ///////////////////// class TideIsHigh: public Event { int dock; public: TideIsHigh (int time, int dockNumber): Event(time), dock(dockNumber) {} virtual void doIt (Simulation& sim); }; void TideIsHigh::doIt (Simulation& sim) { sim.dockIsAccessible[dock] = true; // schedule next high tide sim.events.push(OrderedEvent(new TideIsHigh(sim.time+sim.lowTideDelta, dock))); if (sim.sunIsUp) { if (sim.docked[dock].size() > 0) { // We may have put in at this dock for the prior night // (we might have already left, but, if so, we're still // safe because all these arrivals will be ignored) sim.scheduleArrivalsFrom(dock); } else if (sim.offshore[dock].size() > 0) // Has canoe been waiting offshore? { if (sim.docked[dock].size() == 0 || sim.offshore[dock].size() < sim.docked[dock].size()) sim.docked[dock] = sim.offshore[dock]; sim.offshore[dock].clear(); } } CERR("Rising tide at dock " << dock << "\t"); sim.debug(cerr); } /////////////////////////////////////////////////////////////// void Simulation::run() { bool done = false; while (!done) { OrderedEvent ev = events.top(); events.pop(); time = ev.event->time; done = day() >= maxdays || docked[nDocks].size() > 0; if (!done) ev.event->doIt(*this); if (debugging && docked[nDocks].size() >0) { cerr << "Reached last dock: "; for (int i = 0; i < docked[nDocks].size(); ++i) cerr << docked[nDocks][i] << " "; cerr << endl; } } } void Simulation::report() { int d = (day() < maxdays) ? day() : maxdays-1; if (docked[nDocks].size() == 0) cout << "NO ITINERARY POSSIBLE" << endl; else { if (docked[nDocks].back() != nDocks) docked[nDocks].push_back(nDocks); vector::iterator b = docked[nDocks].begin(); b++; copy (b, docked[nDocks].end(), ostream_iterator(cout, " ")); cout << endl; } } void Simulation::debug(ostream& out) { if (debugging) { out << "Time: " << formattedTime(time) << "\tAt: "; for (int i = 0; i <= nDocks; ++i) if (docked[i].size() > 0) out << " " << i; out << "\tAvailable:"; for (int i = 0; i <= nDocks; ++i) if (dockIsAccessible[i]) out << " " << i; out << endl; } } Simulation::Simulation (istream& in, int maxDays) { maxdays = maxDays; in >> speed; speed = speed / (60.0 * 60.0); // convert to miles per scond sunRise0 = readTime(in); sunRiseDelta = readTime(in); sunSet0 = readTime(in); sunSetDelta = readTime(in); lowTide0 = readTime(in); lowTideDelta = readTime(in); in >> nDocks; dockLocations = new double[nDocks+1]; dockTideInterval = new int[nDocks+1]; for (int i = 0; i <= nDocks; ++i) in >> dockLocations[i] >> dockTideInterval[i]; dockIsAccessible = new bool[nDocks+1]; fill_n (dockIsAccessible, nDocks+1, true); docked = new vector[nDocks+1]; docked[0].push_back(0); offshore = new vector[nDocks+1]; sunIsUp = false; lastDockReached = 0; time = 0; nextSunset = sunSet0; // Schedule ths initial sunrise, sunt, and tidal events events.push(OrderedEvent(new SunRise(sunRise0))); events.push(OrderedEvent(new SunSet(sunSet0))); for (int d = 0; d <= nDocks; ++d) { int duration = dockTideInterval[d]*hoursToSeconds; if (duration > 0) { events.push (OrderedEvent (new TideIsLow(lowTide0 - duration, d))); events.push (OrderedEvent (new TideIsHigh(lowTide0 + duration, d))); } } } void tidal (istream& in) { int maxDays; in >> maxDays; while (maxDays > 0) { Simulation s(in, maxDays); s.run(); s.report(); in >> maxDays; } } int main(int argc, char** argv) { if (argc == 1) tidal(cin); else { ifstream in (argv[1]); debugging = true; tidal(in); } return 0; }