Problem:
Problem D:
Discrete Speed
Consider car trips in a country where there is no friction.
Cars in this country do not have engines.
Once a car started to move at a speed, it keeps moving at the same speed.
There are acceleration devices on some points on the road,
where a car can increase or decrease its speed by 1.
It can also keep its speed there.
Your job in this problem is to write a program
which determines the route with the shortest time
to travel from a starting city to a goal city.
There are several cities in the country,
and a road network connecting them.
Each city has an acceleration device.
As mentioned above, if a car arrives at a city at a speed
v
,
it leaves the city at one of
v
- 1,
v
, or
v
+ 1.
The first road leaving the starting city must be run at the speed 1.
Similarly, the last road arriving at the goal city must be run at the speed 1.
The starting city and the goal city are given.
The problem is to find the best route which leads to the goal city
going through several cities on the road network.
When the car arrives at a city, it cannot immediately go back the road
it used to reach the city.  No U-turns are allowed.
Except this constraint, one can choose any route on the road network.
It is allowed to visit the same city or use the same road multiple times.
The starting city and the goal city may be visited during the trip.
For each road on the network, its distance and speed limit are given.
A car must run a road at a speed less than or equal to its speed limit.
The time needed to run a road is the distance divided by the speed.
The time needed within cities including that for acceleration or deceleration should be ignored.
Input
The input consists of multiple datasets, each in the following format.
n
m
s
g
x
1
y
1
d
1
c
1
...
x
m
y
m
d
m
c
m
Every input item in a dataset is a non-negative integer.
Input items in the same line are separated by a space.
The first line gives the size of the road network.
n
is the number of cities in the network.
You can assume that the number of cities is between 2 and 30, inclusive.
m
is the number of roads between cities, which may be zero.
The second line gives the trip.
s
is the city index of the starting city.
g
is the city index of the goal city.
s
is not equal to
g
.
You can assume that all city indices in a dataset (including the above two)
are between 1 and
n
, inclusive.
The following
m
lines give the details of roads between cities.
The
i
-th road connects two cities with city indices
x
i
and
y
i
,
and has a distance
d
i
(1 ≤
i
≤
m
).
You can assume that the distance is between 1 and 100, inclusive.
The speed limit of the road is specified by
c
i
.
You can assume that the speed limit is between 1 and 30, inclusive.
No two roads connect the same pair of cities.
A road never connects a city with itself.
Each road can be traveled in both directions.
The last dataset is followed by a line containing two zeros
(separated by a space).
Output
For each dataset in the input, one line should b
...(truncated)

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct Node{
	int pos;
	int speed;
	double cost;
	int prev;
};
bool operator < (const Node &a,const Node &b){
	return a.cost > b.cost;
}



int main(){
	int n,m;
	while(cin >> n >> m and n){
		vector<Node> G[n];
		int s,g;
		cin >> s >> g;
		--s,--g;
		for(int i = 0 ; i < m ; i++){
			int a,b,c;
			double d;
			cin >> a >> b >> d >> c;
			--a,--b;
			G[a].push_back({b,c,d,a});
			G[b].push_back({a,c,d,b});
		}
		priority_queue<Node> Q;

		for( auto e : G[s] ){
			int nv = 1;
			if( nv <= e.speed ){
				Q.push({e.pos,nv,e.cost/nv,s});
			}
		}

		//Q.push({s,1,0,31});

		int done[31][31][32] = {};
		while( Q.size() ){
			Node q = Q.top(); Q.pop();
			if( done[q.pos][q.speed][q.prev]++ ) continue;
			if( q.pos == g and q.speed == 1 ){
				printf("%.10lf\n",q.cost);
				goto finish;
			}

			if( q.speed != 0 )
				for( auto e : G[q.pos] ){
					for(int nv = q.speed-1 ; nv <= q.speed + 1 ; nv++){
						if( nv > 0 and nv <= e.speed and e.pos != q.prev ){
							Q.push({e.pos,nv,q.cost+e.cost/nv,q.pos});
						}
					}
				}
		}
		cout << "unreachable" << endl;
		finish:;
	}
}
accuracy: 1
time_ms: 410
memory_kb: 23028
final_rank: 12

code_snippet: #pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")

// #ifndef ONLINE_JUDGE
// #define _GLIBCXX_DEBUG // 配列外参照のエラー
// #endif

// スタンダードライブラリ
#include <bits/stdc++.h>
using namespace std;

// 型関連
using ll = long long;
using lint = long long;
using pll = pair<ll, ll>;
using plll = tuple<ll, ll, ll>;
using pii = pair<int, int>;
using piii = tuple<ll, ll, ll>;
template <class T> using prique = priority_queue<T>;

// 型定数
constexpr ll mod = 998244353;
constexpr ll MOD = 1000000007;
int INF32 = 2e9;
ll INF64 = 9e18;
#define endl '\n';

int dx[4] = {1, 0, -1, 0};
int dy[4] = {0, 1, 0, -1};

/////////////////////////// print関連
template <typename T> void print(vector<T> A);
void print();
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail);
void print(string S);
template <typename T> void print(vector<vector<T>> &F);

inline void Yes(bool f);

///////////////////ここから//////////////////////
using T = tuple<double, int, int, int>;
using piiii = tuple<int, int, int, int>;
bool solve() {
    int N, M;
    cin >> N >> M;
    if (N == 0) {
        return false;
    }
    int s, g;
    cin >> s >> g;
    s--;
    g--;
    vector<vector<piiii>> G(N);
    for (int i = 0; i < M; i++) {
        int x, y, d, c;
        cin >> x >> y >> d >> c;
        x--;
        y--;
        G[x].emplace_back(y, d, c, i);
        G[y].emplace_back(x, d, c, i);
    }
    int max_speed = 31;
    vector<vector<vector<double>>> dist(
        N, vector<vector<double>>(max_speed, vector<double>(M + 1, 1e15)));
    vector<vector<vector<int>>> f(
        N, vector<vector<int>>(max_speed, vector<int>(M + 1, 0)));

    priority_queue<T, vector<T>, greater<T>> que;
    dist[s][0][M] = 0;
    que.emplace(0.0, s, 0, M);
    while (!que.empty()) {
        auto [d, v, s, m] = que.top();
        que.pop();
        if (f[v][s][m]) {
            continue;
        }
        f[v][s][m] = 1;
        for (int ns = s - 1; ns < s + 2; ns++) {
            if (ns < 1) {
                continue;
            }
            for (int n = 0; n < G[v].size(); n++) {
                auto [nv, l, s_limit, nm] = G[v][n];
                if (s_limit < ns || nm == m || f[nv][ns][nm]) {
                    continue;
                }
                double nd = d + (double)l / ns;

                if (dist[nv][ns][nm] > nd) {
                    dist[nv][ns][nm] = nd;
                    que.emplace(nd,nv,ns,nm);
                }
            }
        }
    }

    cout << fixed << setprecision(10);
    double ans = 1e15;
    for (int i = 0; i < M; i++) {
        ans=min(ans,dist[g][1][i]);
    }
    if (ans > 1e14) {
        print("unreachable");
    } else {
        print(ans);
    }

    return true;
}

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    while (solve())
        ;
}

////////////////////print/////////////////////////
// 1次元ベクトルを出力する
template <typename T> void print(vector<T> A) {
    if (A.size() == 0) {
        return;
    }
    for (size_t i = 0; i < A.size() - 1; i++) {
        cout << A[i] << ' ';
    }
    cout << A[A.size() - 1] << endl;
    return;
}

// 2次元ベクトルを出力する
template <typename T> void print(vector<vector<T>> &F) {
    for (size_t i = 0; i < F.size(); i++) {
        for (size_t j = 0; j < F[i].size(); j++) {
            cout << F[i][j];
            if (j < F[i].size() - 1) {
                cout << ' ';
            }
        }
        cout << endl;
    }
}

// 空白行を出力するprint
void print() { cout << endl; }

// 数値・文字列を空白区切りで出力する. print(a,b)など
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    cout << head;
    if (sizeof...(tail) != 0)
        cout << " ";
    print(forward<Tail>(tail)...);
}

void print(string S) { cout << S << endl; }

//////////////出力関連

inline void Yes(bool f) {
    if (f) {
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }
}
accuracy: 1
time_ms: 40
memory_kb: 9232
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll   = long long;
using edge = tuple<int, double, int>;
using tu   = tuple<double, int, int, int>;

constexpr double INF = 2e9;
constexpr int LIM    = 31;

void solve(int n, int m, int s, int g, vector<vector<edge>> E) {
    priority_queue<tu, vector<tu>, greater<>> pq;
    vector dist(n, vector(LIM, vector(n, INF)));
    pq.emplace(0.0, s, 0, s);
    dist[s][0][s] = 0.0;
    while (!pq.empty()) {
        auto [cost, u, speed, prev_v] = pq.top();
        pq.pop();
        if (dist[u][speed][prev_v] < cost) {
            continue;
        }

        for (auto [v, d, lim_speed] : E[u]) {
            if (v == prev_v) {
                continue;
            }

            for (int add = -1; add <= 1; add++) {
                int next_speed = speed + add;
                if (next_speed > lim_speed || next_speed < 1) {
                    continue;
                }

                double next_cost = cost + (d / next_speed);
                if (dist[v][next_speed][u] > next_cost) {
                    dist[v][next_speed][u] = next_cost;
                    pq.emplace(next_cost, v, next_speed, u);
                }
            }
        }
    }

    double ans = INF;
    for (int i = 0; i < n; i++) {
        ans = min(ans, dist[g][1][i]);
    }
    if (ans == INF) {
        cout << "unreachable" << endl;
    } else {
        printf("%.10f\n", ans);
    }
}

int main() {
    while (true) {
        int n, m;
        cin >> n >> m;
        if (n == 0 && m == 0) {
            break;
        }

        int s, g;
        cin >> s >> g;
        s--;
        g--;

        vector<vector<edge>> E(n);
        for (int i = 0; i < m; i++) {
            int x, y, d, c;
            cin >> x >> y >> d >> c;
            x--;
            y--;
            E[x].emplace_back(y, d, c);
            E[y].emplace_back(x, d, c);
        }
        solve(n, m, s, g, E);
    }
}
accuracy: 1
time_ms: 20
memory_kb: 4624
final_rank: 2

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define rrep(i,start,end) for (ll i = start;i >= (ll)(end);i--)
#define repn(i,end) for(ll i = 0; i <= (ll)(end); i++)
#define reps(i,start,end) for(ll i = start; i < (ll)(end); i++)
#define repsn(i,start,end) for(ll i = start; i <= (ll)(end); i++)
#define each(p,a) for(auto &p:a)
typedef vector<ll> vll;
typedef vector<pair<ll ,ll>> vpll;
typedef vector<vector<ll>> vvll;
typedef set<ll> sll;
typedef map<ll , ll> mpll;
typedef pair<ll ,ll> pll;
typedef tuple<ll , ll , ll> tpl3;
#define LL(...) ll __VA_ARGS__; input(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__; input(__VA_ARGS__)
#define Str(...) string __VA_ARGS__; input(__VA_ARGS__)
#define Ch(...) char __VA_ARGS__; input(__VA_ARGS__)
#define all(a)  (a).begin(),(a).end()
#define UNIQUE(v) v.erase( unique(v.begin(), v.end()), v.end() );
#define sz(x) (ll)x.size()
// << std::fixed << std::setprecision(10)
const ll INF = 1LL << 60;
const ld EPS = 1e-9;
 
ll lceil(ll a,ll b){if(a%b==0){return a/b;}if(a>=0){return (a/b)+1;}else{return -((-a)/b);}}
ll lfloor(ll a,ll b){if(a%b==0){return a/b;}if(a>=0){return (a/b);}else{return -((-a)/b)-1;}}
inline ll positive_mod(ll a,ll m){return (a % m + m)%m;}
inline ll popcnt(ull a){ return __builtin_popcountll(a);}
//0indexed
inline ll topbit(ll a){assert(a != 0);return 63 - __builtin_clzll(a);}
inline ll smlbit(ll a){assert(a != 0);return __builtin_ctzll(a);}
template<class T> bool chmin(T& a, T b){if(a > b){a = b;return true;}return false;}
template<class T> bool chmax(T& a, T b){if(a < b){a = b;return true;}return false;}
template<typename T> std::istream &operator>>(std::istream&is,std::vector<T>&v){for(T &in:v){is>>in;}return is;}
template<typename T> std::ostream &operator<<(std::ostream&os,const std::vector<T>&v){for(auto it=std::begin(v);it!=std::end(v);){os<<*it<<((++it)!=std::end(v)?" ":"");}return os;}
template<typename T1, typename T2>std::ostream &operator<< (std::ostream &os, std::pair<T1,T2> p){os << "{" << p.first << "," << p.second << "}";return os;}
template<class... T>void input(T&... a){(cin >> ... >> a);}
void print(){cout << endl;}
template<class T, class... Ts>void print(const T& a, const Ts&... b){cout << a;((cout << ' ' << b), ...);cout << endl;}
template<class T> void pspace(const T& a){ cout << a << ' ';}
void perr(){cerr << endl;}
template<class T, class... Ts>void perr(const T& a, const Ts&... b){cerr << a;((cerr << ' ' << b), ...);cerr << endl;}
void yes(bool i = true){ return print(i?"yes":"no"); }
void Yes(bool i = true){ return print(i?"Yes":"No"); }
void YES(bool i = true){ return print(i?"YES":"NO"); }
template <class T> vector<T> &operator++(vector<T> &v) {for(auto &e : v) e++;return v;}
template <class T> vector<T> operator++(vector<T> &v, signed) {auto res = v;for(auto &e : v) e++;return res;}
template <class T> vector<T> &operator--(vector<T> &v) {for(auto &e : v) e--;return v;}
template <class T> vector<T> operator--(vector<T> &v, signed) {auto res = v;for(auto &e : v) e--;return res;}
//grid探索用
vector<ll> _ta = {0,0,1,-1,1,1,-1,-1};
vector<ll> _yo = {1,-1,0,0,1,-1,1,-1};
bool isin(ll now_i,ll now_j,ll h,ll w){return (0<=now_i && now_i < h && 0 <= now_j && now_j < w);}
  
ll lpow(ll x,ll n){ll ans = 1;while(n >0){if(n & 1)ans *= x;x *= x;n >>= 1;}return ans;}
ll Modlpow(ll x,ll n,ll m){ll ans = 1;ll a = x%m;while(n >0){if(n & 1){ans *= a;ans%= m;}a *= a;a %= m;n >>= 1;}return ans;} 
const ll MOD9 = 998244353LL;
const ll MOD10 = 1000000007LL;
 
int main(){
  ios::sync_with_stdio(false);cin.tie(nullptr);
  while(true){
    LL(n,m);
    if(n == 0 && m == 0)break;
    LL(s,e);
    s--;e--;
    vector<vector<tpl3>> g(n);
    rep(i,m){
      LL(x,y,d,c);
      x--;y--;
      g[x].push_back({y,d,c});
      g[y].push_back({x,d,c});
    }
    vector dist(n,vector(n,vector<ld>(31,INF)));
    using tpl4 = tuple<ld,ll,ll,ll>;
    priority_queue<tpl4,vector<tpl4>,greater<tpl4>> pq;
    //syote
    for(auto[to,d,c]:g[s]){
      if(1 <=c&&chmin(dist[to][s][1],(ld)d)){
        pq.emplace(dist[to][s][1],to,s,1);
      }
    }
    while(!pq.empty()){
      auto[cost,now,past,v] = pq.top();
      pq.pop();
      if(dist[now][past][v] < cost - EPS)continue;
      for(auto[to,d,c]:g[now])if(to != past){
        repsn(i,-1,1){
          if(v+i>0 &&  v+i<=c&&chmin(dist[to][now][v+i],(ld)d/(v+i)+cost) ){
            pq.emplace(dist[to][now][v+i],to,now,v+i);
          }
        }
      }
    }
    bool ok  = false;
    ld ans = INF;
    rep(i,n){
      if(dist[e][i][1] < INF){
        ok = true;
        chmin(ans,dist[e][i][1]);
      }
    }
    if(ok){
      cout << std::fixed << std::setprecision(10) <<  ans << endl;
    }else{
      cout << "unreachable" << endl;
    }
  }
}
accuracy: 1
time_ms: 20
memory_kb: 5384
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define all(...) std::begin(__VA_ARGS__), std::end(__VA_ARGS__)
#define rall(...) std::rbegin(__VA_ARGS__), std::rend(__VA_ARGS__)
#define OVERLOAD_REP(_1, _2, _3, _4, name, ...) name
#define REP1(n) for(ll i=0;i<(n);i++)
#define REP2(i, n) for (ll i=0;i<(n);i++)
#define REP3(i, a, n) for (ll i=a;i<(n);i++)
#define REP4(i, a, b, n) for(ll i=a;i<(n);i+=b)
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP4, REP3, REP2, REP1)(__VA_ARGS__)
#define OVERLOAD_RREP(_1, _2, _3, _4, name, ...) name
#define RREP1(n) for(ll i=(n)-1;i>=0;i--)
#define RREP2(i, n) for(ll i=(n)-1;i>=0;i--)
#define RREP3(i, a, n) for(ll i=(n)-1;i>=(a);i--)
#define RREP4(i, a, b, n) for(ll i=(n)-1;i>=(a);i-=(b))
#define rrep(...) OVERLOAD_RREP(__VA_ARGS__, RREP4, RREP3, RREP2, RREP1)(__VA_ARGS__)
#define uniq(a) sort(all(a));a.erase(unique(all(a)),end(a))
#define len(n) (long long)(n).size()
using ll = long long;
using ld = long double;
using ull = unsigned long long;
using vi = vector<int>;
using vvi = vector<vi>;
using vvvi = vector<vvi>;
using vll = vector<ll>;
using vvll = vector<vll>;
using vvvll = vector<vvll>;
using vs = vector<string>;
using vvs = vector<vs>;
using vvvs = vector<vvs>;
using vld = vector<ld>;
using vvld = vector<vld>;
using vvvld = vector<vvld>;
using vc = vector<char>;
using vvc = vector<vc>;
using vvvc = vector<vvc>;
using pll = pair<ll,ll>;
using vpll = vector<pll>;
using vvpll = vector<vpll>;

ll intpow(ll a,ll b){
    ll ans = 1;
    while (b){
        if (b & 1){
            ans *= a;
        }
        a *= a;
        b /= 2;
    }
    return ans;
}
ll modpow(ll a,ll b,ll c){
    ll ans = 1;
    while (b){
        if (b & 1){
            ans *= a;
            ans %= c;
        }
        a *= a;
        a %= c;
        b /= 2;
    }
    return ans;
}

template<class... T>
void input(T&... a){
    (cin >> ... >> a);
}

#define INT(...) int __VA_ARGS__; input(__VA_ARGS__)
#define LL(...) ll __VA_ARGS__; input(__VA_ARGS__)
#define ULL(...) ull __VA_ARGS__; input(__VA_ARGS__)
#define LD(...) ld __VA_ARGS__; input(__VA_ARGS__)
#define STR(...) string __VA_ARGS__; input(__VA_ARGS__)
#define CHA(...) char __VA_ARGS__; input(__VA_ARGS__)
#define VLL(name,length) vll name(length);rep(i,length){cin >> name[i];}
#define VVLL(name,h,w) vvll name(h,vll(w));rep(i,h)rep(j,w){cin >> name[i][j];}
#define VVVLL(name,a,b,c) vvvll name(a,vvll(b,vll(c)));rep(i,a)rep(j,b)rep(k,c){cin >> name[i][j][k];}
#define VI(name,length) vi name(length);rep(i,length){cin >> name[i];}
#define VVI(name,h,w) vvi name(h,vi(w));rep(i,h)rep(j,w){cin >> name[i][j];}
#define VVVI(name,a,b,c) vvvi name(a,vvll(b,vi(c)));rep(i,a)rep(j,b)rep(k,c){cin >> name[i][j][k];}
#define VLD(name,length) vld name(length);rep(i,length){cin >> name[i];}
#define VVLD(name,h,w) vvld name(h,vld(w));rep(i,h)rep(j,w){cin >> name[i][j];}
#define VVVLD(name,a,b,c) vvvld name(a,vvld(b,vld(c)));rep(i,a)rep(j,b)rep(k,c){cin >> name[i][j][k];}
#define VC(name,length) vc name(length);rep(i,length){cin >> name[i];}
#define VVC(name,h,w) vvc name(h,vc(w));rep(i,h)rep(j,w){cin >> name[i][j];}
#define VVVC(name,a,b,c) vvvc name(a,vvc(b,vc(c)));rep(i,a)rep(j,b)rep(k,c){cin >> name[i][j][k];}
#define VS(name,length) vs name(length);rep(i,length){cin >> name[i];}
#define VVS(name,h,w) vvs name(h,vs(w));rep(i,h)rep(j,w){cin >> name[i][j];}
#define VVVS(name,a,b,c) vvvs name(a,vvs(b,vs(c)));rep(i,a)rep(j,b)rep(k,c){cin >> name[i][j][k];}
#define PLL(name) pll name;cin>>name.first>>name.second;
#define VPLL(name,length) vpll name(length);rep(i,length){cin>>name[i].first>>name[i].second;}

void print(){cout << "\n";}

template <typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, const std::pair<T1, T2>& p) {
    os << "(" << p.first << ", " << p.second << ")";
    return os;
}

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& vec) {
    os << "[";
    for (size_t i = 0; i < vec.size(); ++i) {
        os << vec[i];
        if (i + 1 < vec.size()) os << ", ";
    }
    os << "]";
    return os;
}

template <typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, const std::vector<std::pair<T1, T2>>& a) {
    os << "[";
    for (size_t j = 0; j < a.size(); ++j) {
        os << "(" << a[j].first << ", " << a[j].second << ")";
		if (j + 1 < a.size()) os << ", ";
    }
	os << "]";
    return os;
}

template <typename T1, typename T2>
std::ostream& operator<<(std::ostream& os, const std::vector<std::vector<std::pair<T1, T2>>>& mat) {
	os << "[";
    for (size_t i = 0; i < mat.size(); ++i) {
		os << "[";
        for (size_t j = 0; j < mat[i].size(); ++j) {
            os << "(" << mat[i][j].first << ", " << mat[i][j].second << ")";
			if (j + 1 < mat[i].size()) os << ", ";
        }
		os << "]";
		if (i + 1 < mat.size()) os << ", ";
    }
	os << "]";
    return os;
}

template <typename T>
std::ostream& operator<<(std::ostream& os, const std::set<T>& s) {
    os << "{";
    bool first = true;
    for (const auto& x : s) {
        if (!first) os << ", ";
        os << x;
        first = false;
    }
    os << "}";
    return os;
}

template <typename K, typename V>
std::ostream& operator<<(std::ostream& os, const std::map<K, V>& m) {
    os << "{";
    bool first = true;
    for (const auto& [key, val] : m) {
        if (!first) os << ", ";
        os << key << ": " << val;
        first = false;
    }
    os << "}";
    return os;
}

template<class T, class... Ts>
void print(const T& a, const Ts&... b){cout << a;(cout << ... << (cout << ' ', b));cout << '\n';}

void write(){cout << "\n";}
template<class T, class... Ts>
void write(const T& a, const Ts&... b){cout << a;(cout << ... << (cout << ' ', b));cout << '\n';}
void write(vll x){rep(i,len(x)){cout << x[i];if(i!=len(x)-1){cout << " ";}else{cout << '\n';}}}
void write(vvll x){rep(i,len(x))rep(j,len(x[i])){cout << x[i][j];if(j!=len(x[i])-1){cout << " ";}else{cout << '\n';}}}
void write(vi x){rep(i,len(x)){cout << x[i];if(i!=len(x)-1){cout << " ";}else{cout << '\n';}}}
void write(vvi x){rep(i,len(x))rep(j,len(x[i])){cout << x[i][j];if(j!=len(x[i])-1){cout << " ";}else{cout << '\n';}}}
void write(vvvi x){rep(i,len(x))rep(j,len(x[i]))rep(k,len(x[i][j])){cout << x[i][j][k];if(k!=len(x[i][j])-1){cout << " ";}else if(j!=len(x[i])-1){cout << " | ";}else{cout << '\n';}}}
void write(vld x){rep(i,len(x)){cout << x[i];if(i!=len(x)-1){cout << " ";}else{cout << '\n';}}}
void write(vvld x){rep(i,len(x))rep(j,len(x[i])){cout << x[i][j];if(j!=len(x[i])-1){cout << " ";}else{cout << '\n';}}}
void write(vvvld x){rep(i,len(x))rep(j,len(x[i]))rep(k,len(x[i][j])){cout << x[i][j][k];if(k!=len(x[i][j])-1){cout << " ";}else if(j!=len(x[i])-1){cout << " | ";}else{cout << '\n';}}}
void write(vc x){rep(i,len(x)){cout << x[i];if(i!=len(x)-1){cout << " ";}else{cout << '\n';}}}
void write(vvc x){rep(i,len(x))rep(j,len(x[i])){cout << x[i][j];if(j!=len(x[i])-1){cout << " ";}else{cout << '\n';}}}
void write(vvvc x){rep(i,len(x))rep(j,len(x[i]))rep(k,len(x[i][j])){cout << x[i][j][k];if(k!=len(x[i][j])-1){cout << " ";}else if(j!=len(x[i])-1){cout << " | ";}else{cout << '\n';}}}
void write(vs x){rep(i,len(x)){cout << x[i];if(i!=len(x)-1){cout << " ";}else{cout << '\n';}}}
void write(vvs x){rep(i,len(x))rep(j,len(x[i])){cout << x[i][j];if(j!=len(x[i])-1){cout << " ";}else{cout << '\n';}}}
void write(vvvs x){rep(i,len(x))rep(j,len(x[i]))rep(k,len(x[i][j])){cout << x[i][j][k];if(k!=len(x[i][j])-1){cout << " ";}else if(j!=len(x[i])-1){cout << " | ";}else{cout << '\n';}}}
void write(pll x){cout << x.first << ' ' << x.second << '\n';}
void write(vpll x){rep(i,len(x)){cout << x[i].first << ' ' << x[i].second << '\n';}}
void write(vvpll x){rep(i,len(x))rep(j,len(x[i])){cout << x[i][j].first << ' ' << x[i][j].second;if(j!=len(x[i])-1){cout << " ";}else{cout << '\n';}}}

template <typename T>
T sum(const std::vector<T>& v) {
    return std::accumulate(v.begin(), v.end(), T(0));
}

template<class T> bool chmin(T& a, const T& b){ if(a > b){ a = b; return 1; } return 0; }
template<class T> bool chmax(T& a, const T& b){ if(a < b){ a = b; return 1; } return 0; }
template<class T, class U> bool chmin(T& a, const U& b){ if(a > T(b)){ a = b; return 1; } return 0; }
template<class T, class U> bool chmax(T& a, const U& b){ if(a < T(b)){ a = b; return 1; } return 0; }

using vvvvld = vector<vvvld>;
using S = tuple<ld,ll,ll,ll>;
int main(){
	ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
    
    while(1){
        LL(n,m);
        if(n == 0 && m == 0){break;}
        LL(s,g);
        s--;
        g--;
        vector<vector<tuple<ll,ll,ll>>> edge(n);
        rep(i,m){
            LL(x,y,d,c);
            x--;
            y--;
            edge[x].push_back({y,d,c});
            edge[y].push_back({x,d,c});
        }
        vvvld dp(n,vvld(n,vld(31,1e100)));
        dp[s][s][0] = 0;
        priority_queue<S,vector<S>,greater<S>> q;
        q.push({0,s,s,0});
        while(!q.empty()){
            auto [d,now,p,v] = q.top();
            q.pop();
            if(dp[now][p][v] > d){continue;}
            for(auto [to,l,limit]:edge[now]){
                rep(u,v-1,v+2){
                    if(to != p && 1 <= u && u <= limit && dp[to][now][u] > dp[now][p][v] + ((ld)l / (ld)u)){
                        dp[to][now][u] = dp[now][p][v] + ((ld)l / (ld)u);
                        q.push({dp[to][now][u],to,now,u});
                    }
                }
            }
        }
        cout << fixed << setprecision(16);
        ld ans = 1e100;
        rep(i,n){
            chmin(ans,dp[g][i][1]);
        }
        if(ans > (ld)1e99){
            cout << "unreachable" << endl;
            continue;
        }
        cout << ans << endl;
    }
    
}
accuracy: 1
time_ms: 30
memory_kb: 5384
final_rank: 7

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i = (int)(a); i < (int)(b); i++)
#define rrep(i, a, b) for (int i = (int)(b)-1; i >= (int)(a); i--)
#define ALL(v) (v).begin(), (v).end()
#define UNIQUE(v) sort(ALL(v)), (v).erase(unique(ALL(v)), (v).end())
#define SZ(v) (int)v.size()
#define MIN(v) *min_element(ALL(v))
#define MAX(v) *max_element(ALL(v))
#define LB(v, x) int(lower_bound(ALL(v), (x)) - (v).begin())
#define UB(v, x) int(upper_bound(ALL(v), (x)) - (v).begin())

using uint = unsigned int;
using ll = long long int;
using ull = unsigned long long;
using i128 = __int128_t;
using u128 = __uint128_t;
const int inf = 0x3fffffff;
const ll INF = 0x1fffffffffffffff;

template <typename T> inline bool chmax(T &a, T b) {
    if (a < b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T> inline bool chmin(T &a, T b) {
    if (a > b) {
        a = b;
        return 1;
    }
    return 0;
}
template <typename T, typename U> T ceil(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? (x + y - 1) / y : x / y);
}
template <typename T, typename U> T floor(T x, U y) {
    assert(y != 0);
    if (y < 0)
        x = -x, y = -y;
    return (x > 0 ? x / y : (x - y + 1) / y);
}
template <typename T> int popcnt(T x) {
    return __builtin_popcountll(x);
}
template <typename T> int topbit(T x) {
    return (x == 0 ? -1 : 63 - __builtin_clzll(x));
}
template <typename T> int lowbit(T x) {
    return (x == 0 ? -1 : __builtin_ctzll(x));
}

template <class T, class U>
ostream &operator<<(ostream &os, const pair<T, U> &p) {
    os << "P(" << p.first << ", " << p.second << ")";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const vector<T> &vec) {
    os << "{";
    for (int i = 0; i < vec.size(); i++) {
        os << vec[i] << (i + 1 == vec.size() ? "" : ", ");
    }
    os << "}";
    return os;
}
template <typename T, typename U>
ostream &operator<<(ostream &os, const map<T, U> &map_var) {
    os << "{";
    for (auto itr = map_var.begin(); itr != map_var.end(); itr++) {
        os << "(" << itr->first << ", " << itr->second << ")";
        itr++;
        if (itr != map_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
template <typename T> ostream &operator<<(ostream &os, const set<T> &set_var) {
    os << "{";
    for (auto itr = set_var.begin(); itr != set_var.end(); itr++) {
        os << *itr;
        ++itr;
        if (itr != set_var.end())
            os << ", ";
        itr--;
    }
    os << "}";
    return os;
}
#ifdef LOCAL
#define show(...) _show(0, #__VA_ARGS__, __VA_ARGS__)
#else
#define show(...) true
#endif
template <typename T> void _show(int i, T name) {
    cerr << '\n';
}
template <typename T1, typename T2, typename... T3>
void _show(int i, const T1 &a, const T2 &b, const T3 &...c) {
    for (; a[i] != ',' && a[i] != '\0'; i++)
        cerr << a[i];
    cerr << ":" << b << " ";
    _show(i + 1, a, c...);
}

#include <unistd.h>

namespace fastio {
static constexpr uint32_t SZ = 1 << 17;
char ibuf[SZ];
char obuf[SZ];
char out[100];
// pointer of ibuf, obuf


uint32_t pil = 0, pir = 0, por = 0;

struct Pre {
    char num[10000][4];
    constexpr Pre() : num() {
        for (int i = 0; i < 10000; i++) {
            int n = i;
            for (int j = 3; j >= 0; j--) {
                num[i][j] = n % 10 | '0';
                n /= 10;
            }
        }
    }
} constexpr pre;

inline void load() {
    memmove(ibuf, ibuf + pil, pir - pil);
    pir = pir - pil + fread(ibuf + pir - pil, 1, SZ - pir + pil, stdin);
    pil = 0;
    if (pir < SZ)
        ibuf[pir++] = '\n';
}

inline void flush() {
    fwrite(obuf, 1, por, stdout);
    por = 0;
}

void rd(char &c) {
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
}

void rd(string &x) {
    x.clear();
    char c;
    do {
        if (pil + 1 > pir)
            load();
        c = ibuf[pil++];
    } while (isspace(c));
    do {
        x += c;
        if (pil == pir)
            load();
        c = ibuf[pil++];
    } while (!isspace(c));
}

template <typename T> void rd_real(T &x) {
    string s;
    rd(s);
    x = stod(s);
}

template <typename T> void rd_integer(T &x) {
    if (pil + 100 > pir)
        load();
    char c;
    do
        c = ibuf[pil++];
    while (c < '-');
    bool minus = 0;
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (c == '-') {
            minus = 1, c = ibuf[pil++];
        }
    }
    x = 0;
    while ('0' <= c) {
        x = x * 10 + (c & 15), c = ibuf[pil++];
    }
    if constexpr (is_signed<T>::value || is_same_v<T, i128>) {
        if (minus)
            x = -x;
    }
}

void rd(int &x) {
    rd_integer(x);
}
void rd(ll &x) {
    rd_integer(x);
}
void rd(i128 &x) {
    rd_integer(x);
}
void rd(uint &x) {
    rd_integer(x);
}
void rd(ull &x) {
    rd_integer(x);
}
void rd(u128 &x) {
    rd_integer(x);
}
void rd(double &x) {
    rd_real(x);
}
void rd(long double &x) {
    rd_real(x);
}

template <class T, class U> void rd(pair<T, U> &p) {
    return rd(p.first), rd(p.second);
}
template <size_t N = 0, typename T> void rd_tuple(T &t) {
    if constexpr (N < std::tuple_size<T>::value) {
        auto &x = std::get<N>(t);
        rd(x);
        rd_tuple<N + 1>(t);
    }
}
template <class... T> void rd(tuple<T...> &tpl) {
    rd_tuple(tpl);
}

template <size_t N = 0, typename T> void rd(array<T, N> &x) {
    for (auto &d : x)
        rd(d);
}
template <class T> void rd(vector<T> &x) {
    for (auto &d : x)
        rd(d);
}

void read() {}
template <class H, class... T> void read(H &h, T &...t) {
    rd(h), read(t...);
}

void wt(const char c) {
    if (por == SZ)
        flush();
    obuf[por++] = c;
}
void wt(const string s) {
    for (char c : s)
        wt(c);
}
void wt(const char *s) {
    size_t len = strlen(s);
    for (size_t i = 0; i < len; i++)
        wt(s[i]);
}

template <typename T> void wt_integer(T x) {
    if (por > SZ - 100)
        flush();
    if (x < 0) {
        obuf[por++] = '-', x = -x;
    }
    int outi;
    for (outi = 96; x >= 10000; outi -= 4) {
        memcpy(out + outi, pre.num[x % 10000], 4);
        x /= 10000;
    }
    if (x >= 1000) {
        memcpy(obuf + por, pre.num[x], 4);
        por += 4;
    } else if (x >= 100) {
        memcpy(obuf + por, pre.num[x] + 1, 3);
        por += 3;
    } else if (x >= 10) {
        int q = (x * 103) >> 10;
        obuf[por] = q | '0';
        obuf[por + 1] = (x - q * 10) | '0';
        por += 2;
    } else
        obuf[por++] = x | '0';
    memcpy(obuf + por, out + outi + 4, 96 - outi);
    por += 96 - outi;
}

template <typename T> void wt_real(T x) {
    ostringstream oss;
    oss << fixed << setprecision(15) << double(x);
    string s = oss.str();
    wt(s);
}

void wt(int x) {
    wt_integer(x);
}
void wt(ll x) {
    wt_integer(x);
}
void wt(i128 x) {
    wt_integer(x);
}
void wt(uint x) {
    wt_integer(x);
}
void wt(ull x) {
    wt_integer(x);
}
void wt(u128 x) {
    wt_integer(x);
}
void wt(double x) {
    wt_real(x);
}
void wt(long double x) {
    wt_real(x);
}

template <class T, class U> void wt(const pair<T, U> val) {
    wt(val.first);
    wt(' ');
    wt(val.second);
}
template <size_t N = 0, typename T> void wt_tuple(const T t) {
    if constexpr (N < std::tuple_size<T>::value) {
        if constexpr (N > 0) {
            wt(' ');
        }
        const auto x = std::get<N>(t);
        wt(x);
        wt_tuple<N + 1>(t);
    }
}
template <class... T> void wt(tuple<T...> tpl) {
    wt_tuple(tpl);
}
template <class T, size_t S> void wt(const array<T, S> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}
template <class T> void wt(const vector<T> val) {
    auto n = val.size();
    for (size_t i = 0; i < n; i++) {
        if (i)
            wt(' ');
        wt(val[i]);
    }
}

void print() {
    wt('\n');
}
template <class Head, class... Tail> void print(Head &&head, Tail &&...tail) {
    wt(head);
    if (sizeof...(Tail))
        wt(' ');
    print(forward<Tail>(tail)...);
}
void __attribute__((destructor)) _d() {
    flush();
}
} // namespace fastio


using fastio::flush;
using fastio::print;
using fastio::read;

inline void first(bool i = true) {
    print(i ? "first" : "second");
}
inline void Alice(bool i = true) {
    print(i ? "Alice" : "Bob");
}
inline void Takahashi(bool i = true) {
    print(i ? "Takahashi" : "Aoki");
}
inline void yes(bool i = true) {
    print(i ? "yes" : "no");
}
inline void Yes(bool i = true) {
    print(i ? "Yes" : "No");
}
inline void No() {
    print("No");
}
inline void YES(bool i = true) {
    print(i ? "YES" : "NO");
}
inline void NO() {
    print("NO");
}
inline void Yay(bool i = true) {
    print(i ? "Yay!" : ":(");
}
inline void Possible(bool i = true) {
    print(i ? "Possible" : "Impossible");
}
inline void POSSIBLE(bool i = true) {
    print(i ? "POSSIBLE" : "IMPOSSIBLE");
}

/**
 * @brief Fast IO
 */

struct Edge {
    int To;
    double Len;
    int MAXV;
    int ID;
};

int main() {
while(1) {
    int N, M;
    cin >> N >> M;
    if (N == 0 && M == 0) return 0;
    int S, G;
    cin >> S >> G;
    S--, G--;
    vector<vector<Edge>> Graph(N);
    rep(i,0,M) {
        int X, Y, C;
        double D;
        cin >> X >> Y >> D >> C;
        X--, Y--;
        Graph[X].push_back({Y,D,C,i});
        Graph[Y].push_back({X,D,C,i});
    }
    int MAXS = 31;
    M++;
    vector<double> DP(N*MAXS*M,inf);
    priority_queue<pair<double,int>,vector<pair<double,int>>,greater<pair<double,int>>> PQ;
    auto encode = [&](int i, int j, int k) -> int {return i * MAXS * M + j * M + k;};
    auto decode = [&](int a) -> tuple<int,int,int> {return {a / (MAXS*M), (a/M) % MAXS, a%M};};
    DP[encode(S,0,M-1)] = 0;
    PQ.push({0,encode(S,0,M-1)});
    while(!PQ.empty()) {
        pair<double,int> P = PQ.top();
        PQ.pop();
        double Cost = P.first;
        auto [X, V, EN] = decode(P.second);
        if (DP[P.second] < P.first) continue;
        for (Edge E : Graph[X]) {
            if (E.ID == EN) continue;
            int NX = E.To, NEN = E.ID;
            rep(dv,-1,2) {
                int NV = V + dv;
                if (NV <= 0 || E.MAXV < NV) continue;
                double NCost = Cost + E.Len / (double)NV;
                if (chmin(DP[encode(NX,NV,NEN)],NCost)) {
                    PQ.push({NCost,encode(NX,NV,NEN)});
                }
            }
        }
    }
    double ANS = inf;
    for (Edge E : Graph[G]) {
        chmin(ANS, DP[encode(G,1,E.ID)]);
    }
    if (ANS == inf) cout << "unreachable" << endl;
    else printf("%.12f\n", ANS);
}
}
accuracy: 1
time_ms: 20
memory_kb: 7260
final_rank: 8

code_snippet: #include<bits/stdc++.h>
//#include <atcoder/all>
using namespace std;
//using namespace atcoder;

#define all(v) v.begin(),v.end()
using ll = long long;
using ull = unsigned long long;
using vll=vector<ll>;
using vvll = vector<vector<ll>>;
using P = pair<ll,ll>;
using PP=pair<double,tuple<ll,ll,ll>>;
using vp=vector<pair<ll, ll>>;
//using mint=modint1000000007;
//using mint=modint998244353;

const ll INF=1ll<<60;
ll mod10=1e9+7;
ll mod99=998244353;
const double PI = acos(-1);

#define rep(i,n) for (ll i=0;i<n;++i)
#define per(i,n) for(ll i=n-1;i>=0;--i)
#define rep2(i,a,n) for (ll i=a;i<n;++i)
#define per2(i,a,n) for (ll i=a;i>=n;--i)

template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }

bool solve(){
	ll N,M;cin>>N>>M;
	if(N==M&&N==0) return 0;
	ll s,g;cin>>s>>g;
	s--;g--;
	vll X(M),Y(M),D(M),C(M);
	vector<vp> ab(N);
	rep(i,M){
		cin>>X[i]>>Y[i]>>D[i]>>C[i];
		X[i]--;Y[i]--;
		ab[X[i]].push_back({Y[i],i});
		ab[Y[i]].push_back({X[i],i});
	}

	vector dist(N,vector<vector<double>>(50,vector<double>(N,INF)));
	priority_queue<PP,vector<PP>,greater<PP>> pq;
	pq.push({0,{s,0,s}});
	while(pq.size()){
		auto [c,now1]=pq.top();pq.pop();
		auto [now,v,mae]=now1;
	
		if(dist[now][v][mae]!=INF) continue;
		dist[now][v][mae]=c;
		for(auto [to,i]:ab[now]){
			if(to==mae) continue;
			rep2(j,-1,2){
				if(v+j>C[i]||v+j<=0) continue;
				pq.push({c+(double)D[i]/(v+j),{to,v+j,now}});
			}
		}
	}

	double ans=INF;
	rep(i,40) rep(j,N) chmin(ans,dist[g][1][j]);
	if(ans==INF) cout << "unreachable" << endl;
	else cout << ans << endl;
	
	return 1;
}


int main(){
   cin.tie(0);
   ios::sync_with_stdio(false);
   while(solve());
}
accuracy: 1
time_ms: 760
memory_kb: 29428
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using P = pair<ll, ll>;
#define rep(i, a, b) for(ll i = a; i < b; ++i)
#define rrep(i, a, b) for(ll i = a; i >= b; --i)
constexpr ll inf = 4e18;
struct SetupIO {
    SetupIO() {
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout << fixed << setprecision(30);
    }
} setup_io;
int main(void) {
    while(1) {
        int n, m;
        cin >> n >> m;
        if(n == 0 and m == 0) break;
        int s, t;
        cin >> s >> t;
        s--;
        t--;
        vector<vector<pair<double, int>>> g(n * n * 30 + 1);
        rep(i, 0, m) {
            int x, y, d, c;
            cin >> x >> y >> d >> c;
            x--;
            y--;
            rep(j, 1, 31) {
                rep(k, j - 1, j + 2) {
                    if(1 <= k and k <= c) {
                        rep(l, 0, n) {
                            if(l != y) {
                                g[l * n * 30 + x * 30 + j - 1].push_back({1.0 * d / k, x * n * 30 + y * 30 + k - 1});
                            }
                            if(l != x) {
                                g[l * n * 30 + y * 30 + j - 1].push_back({1.0 * d / k, y * n * 30 + x * 30 + k - 1});
                            }
                        }
                    }
                }
            }
            if(y == s) {
                swap(x, y);
            }
            if(x == s) {
                g[n * n * 30].push_back({1.0 * d, x * n * 30 + y * 30});
            }
        }
        vector<double> d(n * n * 30 + 1, inf);
        priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;
        d[n * n * 30] = 0;
        pq.push({d[n * n * 30], n * n * 30});
        while(!pq.empty()) {
            auto [dist, cur] = pq.top();
            pq.pop();
            if(d[cur] < dist) continue;
            for(const auto& [cost, to] : g[cur]) {
                if(d[to] > d[cur] + cost) {
                    d[to] = d[cur] + cost;
                    pq.push({d[to], to});
                }
            }
        }
        double ans = inf;
        rep(i, 0, n) {
            ans = min(ans, d[i * n * 30 + t * 30]);
        }
        if(ans == inf) {
            cout << "unreachable" << '\n';
        } else {
            cout << ans << '\n';
        }
    }
}
accuracy: 1
time_ms: 150
memory_kb: 59984
final_rank: 14

code_snippet: // (⁠◕⁠ᴗ⁠◕⁠✿⁠)

#pragma GCC target("avx2")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include <bits/stdc++.h>
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define srep(i, s, n) for (ll i = s; i < (n); i++)
#define len(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
using namespace std;
template<typename T> using vc = vector<T>;
template<typename T> using vv = vc<vc<T>>;
template<typename T> using vvv = vv<vc<T>>;
using vi = vc<int>;using vvi = vv<int>; using vvvi = vv<vi>;
using ll = long long;using vl = vc<ll>;using vvl = vv<ll>; using vvvl = vv<vl>;
using ld = long double; using vld = vc<ld>; using vvld = vc<vld>; using vvvld = vc<vvld>;
using uint = unsigned int;
using ull = unsigned long long;
const ld pi = 3.141592653589793;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
// const ll mod = 1000000007;
const ll mod = 998244353;
inline bool inside(ll y, ll x, ll H, ll W) {return 0 <= (y) and (y) < (H) and 0 <= (x) and (x) < (W); }

#define debug(var)  do{std::cout << #var << " : \n";view(var);}while(0)
template<typename T> void view(T e){cout << e << endl;}
template<typename T> void view(const vc<T>& v){for(const auto& e : v){ cout << e << " "; } cout << endl;}
template<typename T> void view(const vv<T>& vv){ for(const auto& v : vv){ view(v); } }

tuple<vc<double>, vi> dijkstra(int s, int N, vv<pair<int, double>> &g){
    using P = pair<double, int>;
    vc<double> dist(N, inf);
    vi bef(N);
    priority_queue<P, vc<P>, greater<P>> q;
    dist[s] = 0;
    q.push({0, s});
    while (!q.empty()){
        auto [c, now] = q.top();q.pop();
        if (dist[now] < c) continue;
        for (auto&& [nxt, nc]: g[now]) if (dist[nxt] > c + nc){
            dist[nxt] = c + nc;
            bef[nxt] = now;
            q.push({dist[nxt], nxt}); 
        }
    }
    return {dist, bef};
}

double solve(int N, int M){
    int S, G; cin >> S >> G; S--; G--;
    int K = 40;
    vv<pair<int, double>> g(K * N * N + 1);
    rep(i, M){
        int x, y, d, c; cin >> x >> y >> d >> c; x--; y--;
        rep(j, N) if (y != j && x != j){
            for (int v = 0; v <= c + 1; v++) for (int nv = max(1, v - 1); nv <= min(c, v + 1); nv++){
                g[x * N * K + j * K + v].push_back({y * N * K + x * K + nv, d / (double)nv});
                g[y * N * K + j * K + v].push_back({x * N * K + y * K + nv, d / (double)nv});
            }
        }
    }
    rep(j, N) if (S != j) g[K * N * N].push_back({S * N * K + j * K + 0, 0});
    auto [dist, bef] = dijkstra(K * N * N, K * N * N + 1, g);
    double ans = inf;
    rep(j, N) if (G != j) ans = min(ans, dist[G * N * K + j * K + 1]);
    return ans;
}

int main(){
    vc<double> ans;
    while (true){
        int N, M; cin >> N >> M;
        if (N == 0) break;
        ans.push_back(solve(N, M));
    }
    for (auto x : ans){
        if (x == inf) cout << "unreachable" << endl;
        else cout << fixed << setprecision(16) << x << endl;
    }
}
accuracy: 1
time_ms: 160
memory_kb: 58688
final_rank: 13

code_snippet: #include<bits/stdc++.h>
#define rep(i,n) for(int i=0; i< (n); i++)
#define mkp(i,j) make_pair((i),(j))
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
const int mod = 998244353;
const int inf = (1<<30);

struct edge{
	int to,c,x;
};

struct state{
	int speed,city;
	long double time;
	int U;
	bool operator>(const state& a) const {
		return time > a.time;
	}
};


struct ShortestPath {
	vector<vector<vector<long double>>> ans;
	vector<vector<edge>> g;
	void init(int n){
		ans.resize(31);
		rep(i,31){
			ans[i].resize(31);
			rep(j,31) ans[i][j].resize(31,inf);
		}
		g.resize(31);
	}


	void dijkstra(int s){

		priority_queue<state,vector<state>,greater<state>> que;
		que.push({0,s,0.0,s});
		ans[s][0][s] = 0;
		//cout<<ans[30][30][30]<<endl;
		while(que.size()){
			int now = que.top().city;
			long double cost = que.top().time;
			int speed = que.top().speed;
			int U = que.top().U;
			que.pop();
			//cout<<now<<" "<<speed<<" "<<U<<endl;
			if(ans[now][speed][U] < cost) continue;
			if(speed <= 1) ans[now][0][U] = min(ans[now][0][U],cost);


			for(auto x : g[now]){

				int to = x.to;
				if(to == U) continue;
				long double d = x.x;
				for(int sp = max(speed - 1,1); sp <= min(speed+1,x.c); sp++){
					long double fare = d/(long double)sp;
				//	cout<<to<<" "<<sp<<" "<<now<<" "<<que.size()<<endl;

					if(ans[to][sp][now] > cost+fare){
				//		cout<<"in if"<<endl;
						que.push({sp,to,cost+fare,now});
						ans[to][sp][now] = cost+fare;
					}
				}
			}
		}
	}
};

int main(){
	while(1){
		int n,m;
		cin>>n>>m;
		if(n == 0) break;
		int s,g; cin>>s>>g; s--; g--;
		ShortestPath a;
		a.init(n);
		rep(i,m){
			int x,y,d,c; cin>>x>>y>>d>>c;x--;y--;
			a.g[x].push_back({y,c,d});
			a.g[y].push_back({x,c,d});
		}
		a.dijkstra(s);
		long double ans = inf;
		rep(i,n) ans = min(ans,a.ans[g][0][i]);
		if( ans == inf) cout<<"unreachable"<<endl;
		else cout<<fixed<<setprecision(10)<<ans<<endl;
	}
}
accuracy: 1
time_ms: 30
memory_kb: 5028
final_rank: 6

code_snippet: #include <iostream>
#include <iomanip>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <stack>
#include <cassert>
using namespace std;

template<typename T>
class dijkstra{
  struct vg{
    int t;
    T c;
  };
  vector<pair<int,T>> cost;
  int beg = -1;
  void run(int x){
    auto comp = [](vg a,vg b){
      return a.c>b.c;
    };
    priority_queue<vg,vector<vg>,decltype(comp)> R{comp};
    for(int i = 0; n > i; i++){
      cost[i].second = -1;
    }
    cost[x].first = -1;
    cost[x].second = 0;
    R.push({x,0});
    while(R.size()){
      auto k = R.top();R.pop();
      if(cost[k.t].second != k.c)continue;
      for(int i = 0; A[k.t].size() > i; i++){
        if(cost[A[k.t][i].t].second != -1 && cost[A[k.t][i].t].second <= k.c+A[k.t][i].c)continue;
        cost[A[k.t][i].t].second = k.c+A[k.t][i].c;
        cost[A[k.t][i].t].first = k.t;
        R.push({A[k.t][i].t,k.c+A[k.t][i].c});
      }
    }

  }

public:
  int n;
  vector<vector<vg>> A;
  vector<vector<vg>> Rev;
  dijkstra(int n_):n(n_),A(n_),Rev(n_),cost(n_,{-1,-1}){}

  //双方向
  void push(int s,int v,T c){
    A[s].push_back({v,c});
    A[v].push_back({s,c});
    Rev[s].push_back({v,c});
    Rev[v].push_back({s,c});
  }

  void push_side(int s,int v,T c){
    A[s].push_back({v,c});
    Rev[v].push_back({s,c});
  }

  void build(int x){
    run(x);
    beg = x;
  }

  //restorate any

  vector<int> restoration(int t = -1){
    vector<int> Ret;
    if(beg == -1 || (t != -1 && cost[t].second == -1)){
      Ret.push_back(-1);
      return Ret;
    }
    int ind = t;
    if(ind == -1){
      T tmp = cost[0].second;
      int tmpin = 0;
      for(int i = 0; n > i; i++){
        if(tmp < cost[i].second){
          tmp = cost[i].second;
          tmpin = i;
        }
      }
      ind = tmpin;
    }
    Ret.push_back(ind);
    while(beg != ind){
      Ret.push_back({cost[ind].first});
      ind = cost[ind].first;
    }
    reverse(Ret.begin(),Ret.end());
    return Ret;
  }

  T operator[](int i){
    return cost[i].second;
  }
};
void solve(int n, int m){
  n++;
  dijkstra<double> D(n*n*60);
  int s,g;cin>>s>>g;
  for(int i = 0; m > i; i++){
    int x,y,d,c;cin>>x>>y>>d>>c;
    for(int j = 1; c >= j; j++){
      for(int k = 0; n > k; k++){
        if(k != x && k != y){
          D.push_side((n*x+k)*60+30+(j-1), (n*y+x)*60+(j-1), (double)d/j);
          D.push_side((n*x+k)*60+(j-1), (n*y+x)*60+(j-1), (double)d/j);
          D.push_side((n*y+k)*60+30+(j-1), (n*x+y)*60+(j-1), (double)d/j);
          D.push_side((n*y+k)*60+(j-1), (n*x+y)*60+(j-1), (double)d/j);

        }
      }
    }
  }
  for(int i = 0; n > i; i++){
    for(int j = 1; 30 >= j; j++){
      for(int k = 0; n > k; k++){
        if(i == k)continue;
        if(j != 30){
          D.push_side((n*i+k)*60+(j-1), (n*i+k)*60+30+(j), 0);
        }
        if(j != 1){
          D.push_side((n*i+k)*60+(j-1), (n*i+k)*60+30+(j-2), 0);
        }
      }
    }
  }
  D.build((n*s+0)*60+30);
  double ans = -1;
  for(int i = 0; n > i; i++){
    if(D[(n*g+i)*60] == -1)continue;
    if(ans < 0)ans = D[(n*g+i)*60];
    else ans = min(ans, D[(n*g+i)*60]);
  }
  if(ans == -1){
    cout << "unreachable" << endl;
  }else{
    cout << fixed << setprecision(10) << ans << endl;
  }
}

int main(){
  int n,m;
  while(cin>>n>>m){
    if(n == 0)return 0;
    solve(n,m);
  }
}
accuracy: 1
time_ms: 290
memory_kb: 63832
final_rank: 16

code_snippet: #include<bits/stdc++.h>
using namespace std;
using ld = long double;
using ll = long long;
const ld LINF = 2e18;
const ld EPS = 1e-10;
template<class T> using min_heap = priority_queue<T, vector<T>, greater<T>>;

int main(){
    while(1){
        int N, M; cin >> N >> M;
        if(N == 0 && M == 0) break;
        int S, G; cin >> S >> G; S--, G--;

        // id < N, ver:31, pre:N
        auto norm = [&](int id, int ver, int pre) -> int {
            return (id * 31 + ver) * N + pre;
        };
        auto mron = [&](int v) -> tuple<int, int, int> {
            return make_tuple(v / (31 * N), (v / N) % 31, v % N);
        };

        vector<vector<pair<int, ld>>> Gr(N * 31 * N);
        for(int _ = 0; _ < M; _++){
            int x, y, d, c; cin >> x >> y >> d >> c;
            x--, y--;

            for(int _a = 0; _a < 2; _a++){
                for(int i = 0; i <= 30; i++){
                    for(int j = 0; j < N; j++){
                        if(j == y) continue;
                        int id = norm(x, i, j);
                        for(int k = -1; k <= 1; k++){
                            int nver = i + k;
                            if(nver <= 0 || c < nver) continue;
                            int id2 = norm(y, nver, x);
                            Gr[id].emplace_back(id2, ld(d) / nver);
                        }
                    }
                }
                swap(x, y);
            }
        }

        min_heap<pair<ld, int>> heap;
        vector<ld> dist(N * 31 * N, LINF);
        vector<bool> used(N * 31 * N);
        dist[norm(S, 0, S)] = 0;
        heap.push(make_pair(0, norm(S, 0, S)));
        while(!heap.empty()){
            auto [_, u] = heap.top();
            heap.pop();
            if(used[u]) continue;
            used[u] = 1;
            for(auto [v, cst] : Gr[u]){
                if(dist[u] + cst + EPS < dist[v]){
                    dist[v] = dist[u] + cst;
                    heap.push(make_pair(dist[v], v));
                }
            }
        }

        cout << fixed << setprecision(10);
        ld ans = LINF;
        // if(N == 5){
        //     cout << dist[norm(1, 1, 0)] << endl;
        //     cout << dist[norm(2, 2, 1)] << endl;
        //     cout << dist[norm(3, 2, 2)] << endl;
        //     cout << dist[norm(4, 1, 3)] << endl;
        // }
        for(int i = 0; i < N; i++){
            ans = min(ans, dist[norm(G, 1, i)]);
        }
        if(ans == LINF) cout << "unreachable" << endl;
        else cout << ans << endl;
    }
}
accuracy: 1
time_ms: 240
memory_kb: 116008
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
template<int mod>istream &operator>>(istream &is,static_modint<mod> &a){long long b;is>>b;a=b;return is;}
istream &operator>>(istream &is,modint &a){long long b;cin>>b;a=b;return is;}
#endif
#ifdef LOCAL
#include "debug.h"
#else
#define debug(...) static_cast<void>(0)
#define debugg(...) static_cast<void>(0)
#define esper(...) static_cast<void>(0)
template<typename T1,typename T2>ostream &operator<<(ostream &os,const pair<T1,T2>&p){os<<p.first<<' '<<p.second;return os;}
#endif
using ll=long long;
using ull=unsigned long long;
using P=pair<ll,ll>;
template<typename T>using minque=priority_queue<T,vector<T>,greater<T>>;
template<typename T>bool chmax(T &a,const T &b){return (a<b?(a=b,true):false);}
template<typename T>bool chmin(T &a,const T &b){return (a>b?(a=b,true):false);}
template<typename T1,typename T2>istream &operator>>(istream &is,pair<T1,T2>&p){is>>p.first>>p.second;return is;}
template<typename T>istream &operator>>(istream &is,vector<T> &a){for(auto &i:a)is>>i;return is;}
template<typename T1,typename T2>void operator++(pair<T1,T2>&a,int n){a.first++,a.second++;}
template<typename T1,typename T2>void operator--(pair<T1,T2>&a,int n){a.first--,a.second--;}
template<typename T>void operator++(vector<T>&a,int n){for(auto &i:a)i++;}
template<typename T>void operator--(vector<T>&a,int n){for(auto &i:a)i--;}
#define reps(i,a,n) for(int i=(a);i<(n);i++)
#define rep(i,n) reps(i,0,n)
#define all(x) x.begin(),x.end()
#define pcnt(x) __builtin_popcountll(x)
#define fin(x) return cout<<x<<'\n',static_cast<void>(0)
ll myceil(ll a,ll b){return (a+b-1)/b;}
template<typename T,size_t n,size_t id=0>
auto vec(const int (&d)[n],const T &init=T()){
  if constexpr (id<n)return vector(d[id],vec<T,n,id+1>(d,init));
  else return init;
}
void SOLVE();
int main(){
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout<<fixed<<setprecision(16);
  #ifdef LOCAL
  clock_t start=clock();
  #endif
  int testcase=1;
  //cin>>testcase;
  for(int i=0;i<testcase;i++){
    SOLVE();
  }
  #ifdef LOCAL
  cerr<<"time:";
  cerr<<(clock()-start)/1000;
  cerr<<"ms\n";
  #endif
}
constexpr double eps=1e-10;
void SOLVE(){
  while(true){
    int n,m;
    cin>>n>>m;
    if(n+m==0)break;
    int s,g;
    cin>>s>>g;
    s--,g--;
    vector<vector<tuple<int,int,int>>>to(n);
    rep(i,m){
      int u,v,d,c;
      cin>>u>>v>>d>>c;
      u--,v--;
      to[u].push_back({v,d,c});
      to[v].push_back({u,d,c});
    }
    auto dst=vec<double>({n+1,n+1,31,31},1e18);
    dst[s][n][1][1]=0;
    minque<pair<double,tuple<int,int,int,int>>>que;
    que.push({0,{s,n,1,1}});
    while(!que.empty()){
      auto [d,p]=que.top();
      auto [x,prex,f,g]=p;
      que.pop();
      if(abs(dst[x][prex][f][g]-d)>eps)continue;
      for(auto [i,du,c]:to[x])if(f<=c&&i!=prex){
        double nxt=d+double(du)/f;
        reps(j,-1,2)if(f+j<=30&&f+j>=1&&chmin(dst[i][x][f+j][f],nxt))que.push({nxt,{i,x,f+j,f}});
      }
    }
    double ans=1e18;
    rep(j,n)rep(i,31)chmin(ans,dst[g][j][i][1]);
    if(ans==1e18)cout<<"unreachable"<<endl;
    else cout<<ans<<endl;
  }
}
accuracy: 1
time_ms: 130
memory_kb: 12952
final_rank: 11

code_snippet: #include <bits/stdc++.h>

bool solve() {
    int N, M;
    std::cin >> N >> M;
    if (N == 0 and M == 0) {
        return false;
    }
    int S, G;
    std::cin >> S >> G;
    S--; G--;
    int n{N * N * 35};
    auto f{[&](int v, int p, int s) -> int {
        return v + p * N + s * N * N;
    }};
    std::vector<std::vector<std::pair<int, long double>>> g(n);
    for (int _{} ; _ < M ; _++) {
        int x, y, d, c;
        std::cin >> x >> y >> d >> c;
        x--; y--;
        for (int p{} ; p < N ; p++) {
            for (int s{1} ; s <= c ; s++) {
                long double cost{(long double)d / (long double)s};
                if (p != y) {
                    g[f(x, p, s)].emplace_back(f(y, x, s - 1), cost);
                    g[f(x, p, s)].emplace_back(f(y, x, s), cost);
                    g[f(x, p, s)].emplace_back(f(y, x, s + 1), cost);
                }
                if (p != x) {
                    g[f(y, p, s)].emplace_back(f(x, y, s - 1), cost);
                    g[f(y, p, s)].emplace_back(f(x, y, s), cost);
                    g[f(y, p, s)].emplace_back(f(x, y, s + 1), cost);
                }
            }
        }
    }
    const long double INF{9e18l};
    std::vector<long double> dist(n, INF);
    dist[f(S, S, 1)] = 0;
    using qt = std::pair<long double, int>;
    std::priority_queue<qt, std::vector<qt>, std::greater<qt>> que;
    que.emplace((long double)0, f(S, S, 1));
    while (que.size()) {
        auto [d, v]{que.top()};
        que.pop();
        if (dist[v] < d) continue;
        for (auto [x, c] : g[v]) {
            if (dist[x] > dist[v] + c) {
                dist[x] = dist[v] + c;
                que.emplace(dist[x], x);
            }
        }
    }
    long double ans{INF};
    for (int i{} ; i < N ; i++) {
        ans = std::min(ans, dist[f(G, i, 0)]);
    }
    if (ans >= INF / 2) {
        std::cout << "unreachable" << '\n';
    }
    else {
        std::cout << ans << '\n';
    }
    return true;
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    std::cout << std::fixed << std::setprecision(5);
    while (solve()) ;
}
accuracy: 1
time_ms: 260
memory_kb: 115676
final_rank: 19

code_snippet: #line 2 "cp-library/src/cp-template.hpp"
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull  = unsigned long long;
using i32 = int;
using u32 = unsigned int;
using i64 = long long;
using u64 = unsigned long long;
using i128 = __int128_t;
template < class T > bool chmin(T& a, T b) { if(a > b) { a = b; return true; } return false; }
template < class T > bool chmax(T& a, T b) { if(a < b) { a = b; return true; } return false; }
template < class T, class U > T ceil (T x, U y) { return (x > 0 ? (x + y - 1) / y :           x / y); }
template < class T, class U > T floor(T x, U y) { return (x > 0 ?           x / y : (x - y + 1) / y); }
int popcnt(i32 x) { return __builtin_popcount(x); }
int popcnt(u32 x) { return __builtin_popcount(x); }
int popcnt(i64 x) { return __builtin_popcountll(x); }
int popcnt(u64 x) { return __builtin_popcountll(x); }

#line 2 "cp-library/src/utility/rep_itr.hpp"
template < class T > struct itr_rep {
    T i, d;
    constexpr itr_rep(const T i) noexcept : i(i), d(1) {}
    constexpr itr_rep(const T i, const T d) noexcept : i(i), d(d) {}
    void operator++() noexcept { i += d; }
    constexpr int operator*() const noexcept { return i; }
    constexpr bool operator!=(const itr_rep x) const noexcept { return d > 0 ? i < x.i : i > x.i; }
};

template < class T > struct rep {
    const itr_rep< T > s, t;
    constexpr rep(const T t) noexcept : s(0), t(t) {}
    constexpr rep(const T s, const T t) noexcept : s(s), t(t) {}
    constexpr rep(const T s, const T t, const T d) noexcept : s(s, d), t(t, d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};

template < class T > struct revrep {
    const itr_rep < T > s, t;
    constexpr revrep(const T t) noexcept : s(t - 1, -1), t(-1, -1) {}
    constexpr revrep(const T s, const T t) noexcept : s(t - 1, -1), t(s - 1, -1) {}
    constexpr revrep(const T s, const T t, const T d) noexcept : s(t - 1, -d), t(s - 1, -d) {}
    constexpr auto begin() const noexcept { return s; }
    constexpr auto end  () const noexcept { return t; }
};
#line 3 "cp-library/src/utility/io.hpp"

/* 128bit integer */
istream& operator>>(istream& is, i128& x) {
    std::string s; is >> s;
    int pm = (s[0] == '-');
    x = 0;
    for(int i : rep(pm, int(s.size()))) x = x * 10 + (s[i] - '0');
    if(pm) x *= -1;
    return is;
}
ostream& operator<<(ostream& os, const i128& x) {
    if(x == 0) return os << '0';
    i128 y = x;
    if(y < 0) { os << '-'; y *= -1; }
    std::vector<int> ny;
    while(y > 0) { ny.push_back(y % 10); y /= 10; }
    for(int i : revrep(ny.size())) os << ny[i];
    return os;
}

template < class S, class T > istream& operator>>(istream& is,       std::pair< S, T >& x) { is >> x.first        >> x.second; return is; }
template < class S, class T > ostream& operator<<(ostream& os, const std::pair< S, T >& x) { os << x.first << " " << x.second; return os; }

namespace scanner {
    struct sca {
        template < class T > operator T() {
            T s; std::cin >> s; return s;
        }
    };
    struct vec {
        int n;
        vec(int n) : n(n) {}
        template < class T > operator std::vector< T >() {
            std::vector< T > v(n);
            for(T& x : v) std::cin >> x;
            return v;
        }
    };
    struct mat {
        int h, w;
        mat(int h, int w) : h(h), w(w) {}
        template < class T > operator std::vector< std::vector< T > >() {
            std::vector m(h, std::vector< T >(w));
            for(std::vector< T >& v : m) for(T& x : v) std::cin >> x;
            return m;
        }
    };
    struct speedup {
        speedup() {
            std::cin.tie(0);
            std::ios::sync_with_stdio(0);
        }
    } speedup_instance;
}
scanner::sca in() { return scanner::sca(); }
scanner::vec in(int n) { return scanner::vec(n); }
scanner::mat in(int h, int w) { return scanner::mat(h, w); }

namespace printer {
    void precision(int d) { std::cout << std::fixed << std::setprecision(d); }
    void flush() { std::cout.flush(); }
}

template < class T >
ostream& operator<<(ostream& os, const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) { os << a[i]; if(i != n - 1) os << ' '; }
    return os;
}

int print() { std::cout << '\n'; return 0; }
template < class head, class... tail > int print(head&& h, tail&&... t) {
    std::cout << h; if(sizeof...(tail)) std::cout << ' ';
    return print(std::forward<tail>(t)...);
}
template < class T > int print_n(const std::vector< T > a) {
    int n = a.size();
    for(int i : rep(n)) std::cout << a[i] << "\n";
    return 0;
}


#line 2 "cp-library/src/utility/key_val.hpp"

template < class K, class V >
struct key_val {
    K key; V val;
    key_val() {}
    key_val(K key, V val) : key(key), val(val) {}
    template < std::size_t Index >
    std::tuple_element_t< Index, key_val >& get() {
        if constexpr (Index == 0) return key;
        if constexpr (Index == 1) return val;
    }
};

namespace std {

template < class K, class V > struct tuple_size < key_val< K, V > > : integral_constant< size_t, 2 > {};
template < class K, class V > struct tuple_element < 0, key_val< K, V > > { using type = K; };
template < class K, class V > struct tuple_element < 1, key_val< K, V > > { using type = V; };

}
#line 2 "cp-library/src/utility/vec_op.hpp"
template < class T > key_val< int, T > max_of(const vector< T >& a) {
    int i = std::max_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class T > key_val< int, T > min_of(const vector< T >& a) {
    int i = std::min_element(a.begin(), a.end()) - a.begin();
    return {i, a[i]};
}
template < class S, class T > S sum_of(const vector< T >& a) {
    S sum = 0;
    for(const T x : a) sum += x;
    return sum;
}
template < class S, class T > vector< S > freq_of(const vector< T >& a, T L, T R) {
    vector< S > res(R - L, S(0));
    for(const T x : a) res[x - L] += 1;
    return res;
}
template < class S, class T > struct prefix_sum {
    vector< S > s;
    prefix_sum(const vector< T >& a) : s(a) {
        s.insert(s.begin(), S(0));
        for(int i : rep(a.size())) s[i + 1] += s[i];
    }
    // [L, R)
    S sum(int L, int R) { return s[R] - s[L]; }
};
#line 3 "cp-library/src/utility/heap.hpp"

template < class T > using heap_min = std::priority_queue< T, std::vector< T >, std::greater< T > >;
template < class T > using heap_max = std::priority_queue< T, std::vector< T >, std::less< T > >;

#line 27 "cp-library/src/cp-template.hpp"

#line 1 "cp-library/src/algorithm/bin_search.hpp"
template < class T, class F >
T bin_search(T ok, T ng, F f) {
    while(abs(ng - ok) > 1) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}

template < class T, class F >
T bin_search_real(T ok, T ng, F f, int step = 80) {
    while(step--) {
        T mid = (ok + ng) / 2;
        (f(mid) ? ok : ng) = mid;
    }
    return ok;
}
#line 2 "cp-library/src/algorithm/argsort.hpp"

template < class T > std::vector< int > argsort(const std::vector< T > &a) {
    std::vector< int > ids((int)a.size());
    std::iota(ids.begin(), ids.end(), 0);
    std::sort(ids.begin(), ids.end(), [&](int i, int j) {
        return a[i] < a[j] || (a[i] == a[j] && i < j);
    });
    return ids;
}
#line 1 "macro.hpp"
namespace macro {

using size_type = int;
template < class container > void  sort(container& a) { std::sort(std:: begin(a), std:: end(a)); }
template < class container > void rsort(container& a) { std::sort(std::rbegin(a), std::rend(a)); }
template < class container > void reverse(container& a) { std::reverse(std::begin(a), std::end(a)); }
template < class container > void unique(container& a) {
    std::sort(std::begin(a), std::end(a));
    a.erase(std::unique(std::begin(a), std::end(a)), std::end(a));
}
template < class container > container  sorted(const container& a) { container b = a;  sort(b); return std::move(b); }
template < class container > container rsorted(const container& a) { container b = a; rsort(b); return std::move(b); }
template < class container, class compare > void sort(container& a, const compare& cmp) { std::sort(std::begin(a), std::end(a), cmp); }
template < class container, class compare > container sorted(const container& a, const compare& cmp) { container b = a; sort(b, cmp); return std::move(b); }
template < class container, class value > size_type lower_bound(const container& a, const value& x) { return std::lower_bound(std::begin(a), std::end(a), x) - std::begin(a); }
template < class container, class value > size_type upper_bound(const container& a, const value& x) { return std::upper_bound(std::begin(a), std::end(a), x) - std::begin(a); }

const std::vector<std::pair<size_type, size_type>> dir4 = { {+1,  0}, {-1,  0}, { 0, +1}, { 0, -1} };
const std::vector<std::pair<size_type, size_type>> dir8 = { {-1, -1}, {-1,  0}, {-1, +1}, { 0, -1}, { 0, +1}, {+1, -1}, {+1,  0}, {+1, +1} };

#ifdef _DEBUG
#define debug(x) std::cout << "[" << __LINE__ << "] " << #x << ": " << x << std::endl
#else
#define debug(x)
#endif

template < class container > void concat(container& a, const container& b) {
    a.insert(std::end(a), std::begin(b), std::end(b));
}
std::vector<size_type> iota(const size_type n) {
    std::vector<size_type> I(n);
    std::iota(std::begin(I), std::end(I), 0);
    return I;
}
template < class container > std::vector<size_type> sort_idx(const container& a) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return a[i] < a[j] or (a[i] == a[j] and i < j); });
    return I;
}
template < class container, class compare > std::vector<size_type> sort_idx(const container& a, const compare& cmp) {
    const size_type n = a.size();
    std::vector<size_type> I = iota(n);
    std::sort(std::begin(I), std::end(I), [&](size_type i, size_type j) { return cmp(a[i], a[j]) or (a[i] == a[j] and i < j); });
    return std::move(I);
}

struct grid {
    using size_type = int;
    size_type H, W;
    grid(const size_type H, const size_type W) : H(H), W(W) {}
    bool contains(const size_type i, const size_type j) {
        return 0 <= i and i < H and 0 <= j and j < W;
    }
};

} // namespace macro

using namespace macro;
#line 3 "A.cpp"

ld solve(int n, int m) {
    int s = in(), g = in(); s--, g--;
    vector dist(n, vector(n, 0));
    vector cons(n, vector(n, 0));
    for(int i : rep(m)) {
        int x = in(), y = in(), d = in(), c = in(); x--, y--;
        dist[x][y] = dist[y][x] = d;
        cons[x][y] = cons[y][x] = c;
    }

    const int max_v = 30;
    vector D(n, vector(n + 1, vector(max_v + 1, ld(1e18))));
    D[s][n][0] = 0;
    heap_min<tuple<ld,int,int,int>> q;
    q.push({D[s][n][0], s, n, 0});
    while(not q.empty()) {
        auto [uc, ui, pi, fv] = q.top(); q.pop();
        for(int vi : rep(n)) if(vi != pi) {
            for(int tv = fv - 1; tv <= fv + 1; tv++) if(1 <= tv and tv <= cons[ui][vi]) {
                if(chmin(D[vi][ui][tv], D[ui][pi][fv] + ld(dist[ui][vi]) / tv)) {
                    q.push({D[vi][ui][tv], vi, ui, tv});
                }
            }
        }
    }

    ld ans = 1e18;
    for(int i : rep(n + 1)) chmin(ans, D[g][i][1]);
    return (ans == 1e18 ? -1 : ans);
}

int main() {
    while(true) {
        int n = in(), m = in();
        if(make_pair(n, m) == make_pair(0, 0)) return 0;
        ld ans = solve(n, m);
        if(ans < 0) {
            print("unreachable");
        } else {
            printer::precision(20);
            print(ans);
        }
    }
}
accuracy: 1
time_ms: 30
memory_kb: 4504
final_rank: 4

code_snippet: #include <iostream>
#include <vector>
#include <tuple>
#include <queue>
#include <iomanip>
using namespace std;

int main() {
  int n, m;
  cin >> n >> m;
  while (n || m) {
    // cout << 1 << n << m << endl;
    int s, g, x, y, d, c;
    vector<tuple<int, int, int>> v[31];
    cin >> s >> g;
    for (int i = 0; i < m; i++) {
      cin >> x >> y >> d >> c;
      v[x].push_back({y, d, c});
      v[y].push_back({x, d, c});
    }
    priority_queue<tuple<double, int, int, int>, vector<tuple<double, int, int, int>>, greater<tuple<double, int, int, int>>> pq;
    for (auto i: v[s]) pq.push({(double)get<1>(i), get<0>(i), 1, s});
    double ti;
    bool t[31][31][31] = {};
    c = -1;
    while (!pq.empty()) {
      tie(ti, x, c, y) = pq.top();
      pq.pop();
      if (t[x][y][c]) continue;
      if (x == g && c == 1) break;
      // cout << ti << " " << x << " " << c << " " << y << endl;
      t[x][y][c] = 1;
      for (auto i: v[x]) {
        if (get<0>(i) == y) continue;
        if (c - 1 && c - 1 <= get<2>(i)) pq.push({ti + get<1>(i) / (double)(c-1), get<0>(i), c-1, x});
        if (c <= get<2>(i)) pq.push({ti + get<1>(i) / (double)c, get<0>(i), c, x});
        if (c + 1 <= get<2>(i)) pq.push({ti + get<1>(i) / (double)(c + 1), get<0>(i), c + 1, x});
      }
    }
    if (x == g && c == 1) cout << fixed << setprecision(4) << ti << endl;
    else cout << "unreachable\n";
    cin >> n >> m;
  }
}
accuracy: 1
time_ms: 560
memory_kb: 24000
final_rank: 15

code_snippet: #include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < n; ++i)
typedef long long ll;
using namespace std;
const double INF = 1e20;

template <class T>
struct edge {
    int to;
    T c, d;
    edge(int to, T c, T d) : to(to), c(c), d(d) {}
};

void solve(int N, int M) {
    int S, T;
    cin >> S >> T;
    S--, T--;
    vector<vector<edge<int>>> G(N);
    rep(i, M) {
        int x, y, d, c;
        cin >> x >> y >> d >> c;
        x--, y--;
        G[x].emplace_back(y, c, d);
        G[y].emplace_back(x, c, d);
    }

    vector dist(N, vector(N, vector<double>(31, INF)));
    dist[S][S][0] = 0;
    //  cost, node, pre_node, speed
    using P = tuple<double, int, int, int>;
    priority_queue<P, vector<P>, greater<P>> pq;
    pq.emplace(0, S, S, 0);
    while (!pq.empty()) {
        auto [cost, u, p, s] = pq.top();
        pq.pop();

        if (dist[u][p][s] < cost) continue;
        for (auto [v, c, d] : G[u]) {
            if (v == p) continue;
            for (int ns = s - 1; ns <= s + 1; ++ns) {
                if (ns <= 0 || ns > c) continue;
                if (dist[v][u][ns] > dist[u][p][s] + d / (double)ns) {
                    dist[v][u][ns] = dist[u][p][s] + d / (double)ns;
                    pq.emplace(dist[v][u][ns], v, u, ns);
                }
            }
        }
    }

    double ans = INF;
    rep(i, N) ans = min(ans, dist[T][i][1]);
    if (ans == INF) cout << "unreachable\n";
    else cout << fixed << setprecision(12) << ans << '\n';
}

int main() {
    cin.tie(0)->sync_with_stdio(0);

    int N, M;
    while (cin >> N >> M) {
        if (N == 0 && M == 0) break;
        solve(N, M);
    }

    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 4216
final_rank: 1

code_snippet: #pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx2,popcnt,lzcnt,abm,bmi,bmi2")
// #define _GLIBCXX_DEBUG /* これをするとvectorの配列外参照などがチェックされる */
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;

const bool DEBUG = true;
#define debug(x) \
    if (DEBUG) cerr << __FILE__ << ':' << __LINE__ << ") " << #x << " : " << (x) << endl;

/*
    pre   : 前いた頂点
    now   : 到達した頂点
    speed : 出た時のスピード
*/

using Node = tuple<int, int, int>;

int now(Node n) {
    auto [x, y, z] = n;
    return y;
}

int speed(Node n) {
    auto [x, y, z] = n;
    return z;
}

void solve(int n, int m) {
    map<Node, vector<Node> > G_mp;

    vector<vector<int> > G(n);
    vector<vector<double> > d(n, vector<double>(n, 1e18));
    vector<vector<int> > c(n, vector<int>(n, 0));
    int s, g;
    cin >> s >> g;
    s--;
    g--;
    for (int i = 0; i < m; i++) {
        ll u, v, c_, d_;
        cin >> u >> v >> d_ >> c_;
        u--;
        v--;
        G[u].push_back(v);
        G[v].push_back(u);

        d[u][v] = d_;
        d[v][u] = d_;

        c[v][u] = c_;
        c[u][v] = c_;
    }

    for (int speed = 1; speed <= 30; speed++) {
        // s -> s+1 , s -> s , s -> s-1
        for (int now = 0; now < n; now++) {
            for (int pre : G[now]) {
                if (c[pre][now] == 0) continue;

                Node NOW = {pre, now, speed};

                for (ll nx : G[now]) {
                    if (nx == pre) continue;
                    if (speed <= c[now][nx]) {
                        G_mp[NOW].emplace_back(now, nx, speed);
                        G_mp[NOW].emplace_back(now, nx, speed + 1);
                        G_mp[NOW].emplace_back(now, nx, speed - 1);
                    }
                }
            }
        }
    }

    Node r = {-1, s, 1};

    for (int nx = 0; nx < n; nx++) {
        if (1 <= c[s][nx]) {
            G_mp[r].push_back({s, nx, 1});
            G_mp[r].push_back({s, nx, 2});
        }
    }

    priority_queue<pair<double, Node>, vector<pair<double, Node> >, greater<pair<double, Node> > > pq;
    pq.push({0.0, r});

    map<Node, double> dist;

    double ans = 1e18;

    while (!pq.empty()) {
        auto [D, v] = pq.top();
        pq.pop();

        if (dist[v] >= 1e-8 && dist[v] < D) continue;

        for (Node nx : G_mp[v]) {
            double dst = D + (d[now(v)][now(nx)] / double(speed(v)));

            if (dist[nx] < 1e-9 || dist[nx] > dst) {
                pq.emplace(dst, nx);
                dist[nx] = dst;
                if (now(nx) == g && speed(v) == 1) {
                    ans = min(ans, dst);
                }
            }
        }
    }

    cout.precision(18);
    if (ans > 1e17) {
        cout << "unreachable" << endl;
    } else {
        cout << ans << endl;
    }
}

int main() {
    int n, m;
    while (1) {
        cin >> n >> m;
        if (n == 0 && m == 0) break;
        solve(n, m);
    }
    return 0;
}
accuracy: 1
time_ms: 890
memory_kb: 46712
final_rank: 20

code_snippet: #include <bits/stdc++.h>
using namespace std;

using ll = long long;
#define rep(i, n) for (ll i = 0; i < (n); i++)

template <typename T>
using min_priority_queue = priority_queue<T, vector<T>, greater<T>>;

using ld = long double;
ld INF = 1e300;

struct edge {
    int to, d, c;
    edge(int to, int d, int c) : to(to), d(d), c(c) {}
};

bool solve() {
    int N, M;
    cin >> N >> M;
    if (N == 0 && M == 0) {
        return false;
    }
    int s, g;
    cin >> s >> g;
    s--;
    g--;
    vector<vector<edge>> G(N);
    rep(i, M) {
        int x, y, d, c;
        cin >> x >> y >> d >> c;
        x--;
        y--;
        G[x].push_back(edge(y, d, c));
        G[y].push_back(edge(x, d, c));
    }

    auto tm = [&](int d, int s) -> ld { return (ld)d / (ld)s; };

    auto dijkstra = [&](int start) {
        vector dist(N, vector(40, vector(N, INF)));
        dist[start][0][start] = 0.;
        // time, {idx, speed, prev}
        min_priority_queue<pair<ld, tuple<int, int, int>>> que;
        que.push({0., {start, 0, start}});

        while (!que.empty()) {
            auto [time, data] = que.top();
            que.pop();
            auto [idx, speed, prev] = data;
            if (time != dist[idx][speed][prev]) continue;
            for (auto e : G[idx]) {
                if (prev == e.to) continue;
                for (int as = -1; as <= 1; as++) {
                    int ns = as + speed;
                    if (ns <= 0) continue;
                    if (e.c < ns) continue;
                    ld addtime = tm(e.d, ns);
                    if (dist[e.to][ns][idx] > addtime + time) {
                        dist[e.to][ns][idx] = addtime + time;
                        que.push({addtime + time, {e.to, ns, idx}});
                    }
                }
            }
        }
        return dist;
    };

    auto dists = dijkstra(s);
    // rep(s, 30) {
    //     cout << "+++++  " << s << "  +++++" << endl;
    //     rep(i, N) cout << dists[i][s] << " ";
    //     cout << endl;
    // }

    cout << fixed << setprecision(15);

    ld ans = INF;
    rep(i, N) ans = min(ans, dists[g][1][i]);

    if (ans == INF) {
        cout << "unreachable" << endl;
    } else {
        cout << ans << endl;
    }
    return true;
}

int main() {
    while (solve())
        ;
}
accuracy: 1
time_ms: 30
memory_kb: 4836
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vll>;
#define all(A) A.begin(),A.end()
#define rep(i, n) for (ll i = 0; i < (ll) (n); i++)

struct road{
    ll to;
    ll d;
    ll c;
};
struct city{
    ll n;
    ll p;
    ll v;
};
const double EPS=1e-12;
int main() {

    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    ll N,M,S,T;
    while(cin>>N>>M){
        if(N==0)return 0;
        cin>>S>>T;
        S--;T--;
        vector<vector<road>> G(N);
        rep(i,M){
            ll x,y,d,c;
            cin>>x>>y>>d>>c;
            x--;y--;
            if(x==S||y==T)c=c;
            G[x].push_back(road{y,d,c});
            G[y].push_back(road{x,d,c});
        }
        vector<vector<vector<double>>> D(N,vector<vector<double>>(N,vector<double>(31,1e16)));
        D[S][S][0]=0.0;
        priority_queue<pair<double,vll>,vector<pair<double,vll>>,greater<pair<double,vll>>> Q;   
        Q.push({0.0,{S,S,0}});
        vector<vector<vector<bool>>> seen(N,vector<vector<bool>>(N,vector<bool>(31,0)));
        while(!Q.empty()){
            auto p=Q.top();
            Q.pop();
            double C=p.first;
            ll n=p.second[0];
            ll pn=p.second[1];
            ll v=p.second[2];
            if(seen[n][pn][v])continue;
            seen[n][pn][v]=1;
            for(auto q:G[n]){
                if(pn==q.to)continue;
                for(ll dv=-1;dv<=1;dv++){
                    ll nv=v+dv;
                    if(nv<=0||nv>q.c)continue;
                    if(seen[q.to][n][nv])continue;
                    if(D[q.to][n][nv]>C+double(q.d)/double(nv)+EPS){
                        D[q.to][n][nv]=C+double(q.d)/double(nv);
                        Q.push({D[q.to][n][nv],{q.to,n,nv}});
                    }
                }
            }
            
        }
        double an=1e18;
        rep(i,N)an=min(an,D[T][i][1]);
        if(an>1e15){
                cout<<"unreachable"<<endl;
            }
            else{
                cout<<fixed<<setprecision(16)<<an<<endl;
            }
    }
    
}
accuracy: 1
time_ms: 40
memory_kb: 4748
final_rank: 9