SRM 479 500pt: TheAirTripDivOne
問題概要
都市がN(<400)あり、各都市間には片方向への飛行機が定期的に飛んでいる。都市0から都市N-1までの移動時間がT(<10^8)以下になるようなスケジュールで、空港での滞在時間の最小値を最大化する問題。
考えたこと
practiceで通ったコード
計算量O(log T * E * log E)。
#include <vector> #include <string> #include <numeric> #include <queue> #include <algorithm> #include <sstream> using namespace std; typedef long long int64; struct flight{ int from, to; int64 first, time, term; }; struct state{ int64 dist; int cur; }; bool operator<(const state& lhs, const state& rhs){ return lhs.dist > rhs.dist; } const int MAX_N = 477; const int64 INF = 1LL<<60; vector<flight> graph[MAX_N]; int64 dist[MAX_N]; struct TheAirTripDivOne { int find(int n, vector <string> flights, int time) { //グラフ構成 string line = accumulate(flights.begin(), flights.end(), string()); for(int i=0; i<(int)line.length(); i++)if(line[i] == ','){ line[i] = ' '; } stringstream ss(line); int a,b,c,d,e; while(ss>>a>>b>>c>>d>>e){ a--; b--; graph[a].push_back((flight){a,b,c,d,e}); } if(!check(1, n, time)){ return -1; } int low = 1, high = time + 1; while(high - low > 1){ int mid = (high + low) / 2; if(check(mid, n, time)){ low = mid; } else{ high = mid; } } return low; } bool check(int x, int n, int64 time){ priority_queue<state> que; fill(dist, dist+n, INF); dist[0] = 0; que.push((state){0, 0}); while(!que.empty()){ state tp = que.top(); que.pop(); int64 d = tp.dist; int cur = tp.cur; if(cur == n-1){ return true; } if(d > dist[cur]){ continue; } int64 now = d + (cur==0?0:x); for(int i=0; i<(int)graph[cur].size(); i++){ flight& fly = graph[cur][i]; int64 next = INF; if(now <= fly.first){ next = fly.first + fly.time; } else{ int64 loss = 0; if( (now - fly.first)%fly.term != 0){ loss = fly.term - (now - fly.first)%fly.term; } next = fly.time + now + loss; } if(next <= time && dist[fly.to] > next){ dist[fly.to] = next; que.push((state){next, fly.to}); } } } return false; } };