/** GOKURI */ #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define FNAME "ski.txt" #define cin fin typedef int vert; struct len_t { double tot_effort, tot_len; len_t() : tot_effort(0), tot_len(0) {}; len_t(double eff, double len) : tot_effort(eff), tot_len(len) {}; }; typedef pair cedge; typedef pair > edge; typedef vector edges; typedef map graph; bool operator< (const len_t& a, const len_t& b) { return a.tot_effort / a.tot_len < b.tot_effort / b.tot_len; } #if 1 void trav( graph& G, vert v, vert src, vector< vector >& opt ) { if( !opt[v].empty() ) return; if( v == src ) { opt[v].push_back( len_t(0,0) ); return; } edges& ne = G[v]; for(int i=0; i!=ne.size(); ++i) { vert u = ne[i].first; trav( G, u, src, opt ); for(int j=0; j!=opt[u].size(); ++j) { // opt[u][j] ~ ne[i].second len_t nl(opt[u][j].tot_effort + ne[i].second.first * ne[i].second.second, opt[u][j].tot_len + ne[i].second.second); bool worse = false; for(int k=0; k!=opt[v].size()&&!worse; ++k) { len_t l1 = opt[v][k]; if(l1.tot_len >= nl.tot_len && l1.tot_effort <= nl.tot_effort) worse = true; } if( !worse ) opt[v].push_back(nl); } } } double solver(graph& G, int np, vert src, vert dst) { vector< vector > opt( np ); trav( G, dst, src, opt ); len_t l = *min_element( opt[dst].begin(), opt[dst].end() ); return double(l.tot_effort)/l.tot_len; } #elif 1 double trav(graph& G, vert p, vector visited, const vert dst, const len_t& t) { if(p == dst) return t.tot_effort / t.tot_len; edges es = G[p]; double result = DBL_MAX; for(int i = 0; i < es.size(); i++) { if(visited[es[i].first]) continue; visited[es[i].first] = true; double d = trav(G, es[i].first, visited, dst, len_t(t.tot_effort + es[i].second.first * es[i].second.second, t.tot_len + es[i].second.second)); visited[es[i].first] = false; if(d < result) result = d; } return result; } double solve(graph& G, int np, vert src, vert dst) { vector< deque > lens(np); deque st; double result = DBL_MAX; lens[src].push_back(len_t(0, 0)); st.push_back(src); while(!st.empty()) { const vert v = st.front(); st.pop_front(); sort(lens[v].begin(), lens[v].end()); for(int i = 0; i < lens[v].size(); i++) { const len_t& l1 = lens[v][i]; for(int j = i + 1; j < lens[v].size(); j++) { const len_t& l2 = lens[v][j]; bool worse = false; if(l1.tot_len >= l2.tot_len && l1.tot_effort <= l2.tot_effort) worse = true; if(worse) { lens[v].erase(lens[v].begin() + j); j--; } } } edges es = G[v]; for(int i = 0; i < es.size(); i++) { for(int j = 0; j < lens[v].size(); j++) { len_t newlen = len_t(lens[v][j].tot_effort + es[i].second.first * es[i].second.second, lens[v][j].tot_len + es[i].second.second); lens[es[i].first].push_back(newlen); } st.push_back(es[i].first); } } sort(lens[dst].begin(), lens[dst].end()); return lens[dst][0].tot_effort / lens[dst][0].tot_len; } #else double solve(graph& G, vert src, vert dst) { map shtstlen; bool changed; shtstlen[src] = len_t(0, 0); int cnt = 0; do { changed = false; //cout << cnt++ << endl; for(graph::const_iterator it = G.begin(); it != G.end(); ++it) { const vert v = it->first; const edges& es = it->second; if(!shtstlen.count(v)) continue; for(int i = 0; i < es.size(); i++) { len_t newlen = len_t(shtstlen[v].tot_effort + es[i].second.first * es[i].second.second, shtstlen[v].tot_len + es[i].second.second); if(!shtstlen.count(es[i].first)) { //cout << v << "->" << es[i].first << endl; changed = true; shtstlen[es[i].first] = newlen; } else if(newlen < shtstlen[es[i].first]) { //cout << v << "->" << es[i].first << endl; changed = true; shtstlen[es[i].first] = newlen; } } } } while(changed); return shtstlen[dst].tot_effort / shtstlen[dst].tot_len; } #endif template class ToInt { map mp; vector idmap; int id; public: ToInt(int id = 0) : id(id) {} int operator[] (const T& t) { return mp.count(t) ? mp[t] : (mp[t] = id++); } T id2value(int id) { return idmap[id]; } int size() const { return id; } }; static inline double cost(const double speed) { if(speed <= 60.0) return (70.0 - speed); else return 10.0; //(speed - 50.0); } int main() { ifstream fin(FNAME); if(!fin) return -1; int ncase; cin >> ncase; while(ncase--) { int N, R; cin >> N >> R; ToInt table; int src, dst; cin >> src >> dst; graph g, rg; while(R--) { int f, t; double maxsp, len; cin >> f >> t >> maxsp >> len; g[table[f]].push_back( edge(table[t], make_pair(cost(maxsp), len))); rg[table[t]].push_back(edge(table[f], make_pair(cost(maxsp), len))); } static char buffer[32]; sprintf(buffer, "%.2f", solver(rg, table.size(), table[src], table[dst])); cout << buffer << endl; } return 0; }