Problem p01173 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <algorithm>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define EPS (1e-10)
#define EQ(a, b) (abs((a) - (b)) < EPS)
#define EQV(a, b) (EQ((a).real(), (b).real()) && EQ((a).imag(), (b).imag()))

typedef complex<double> P;
typedef pair<P, P> Edge;
typedef long long ll;

const double PI = 4 * atan(1.0);
const int MAX_SIZE = 10000;

// 内積
double dot(P a, P b) { return (a.real() * b.real() + a.imag() * b.imag()); }
// 外積
double cross(P a, P b) { return (a.real() * b.imag() - a.imag() * b.real()); }
// 点cが直線ab上にあるかないか
int is_point_on_line(P a, P b, P c) { return EQ(cross(b - a, c - a), 0.0); }
// 2直線の直行判定
int is_orthogonal(P a1, P a2, P b1, P b2) {
  return EQ(dot(a1 - a2, b1 - b2), 0.0);
}
// 2直線の平行判定
int is_parallel(P a1, P a2, P b1, P b2) {
  return EQ(cross(a1 - a2, b1 - b2), 0.0);
}
// 点a,bを通る直線と点cの間の距離
double distance_l_p(P a, P b, P c) {
  return abs(cross(b - a, c - a)) / abs(b - a);
}
// 点a,bを端点とする線分と点cとの距離
double distance_ls_p(P a, P b, P c) {
  if (dot(b - a, c - a) < EPS)
    return abs(c - a);
  if (dot(a - b, c - b) < EPS)
    return abs(c - b);
  return abs(cross(b - a, c - a)) / abs(b - a);
}
// 点が多角形の中に存在するかどうか
bool isInPolygon(vector<P> &points, P s) {
  if (points.size() == 1)
    return false;
  vector<P> v;
  for (int i = 0; i < (int)points.size(); i++)
    v.push_back(points[i] - s);
  int sign = 0;
  for (int i = 1; i <= (int)v.size(); i++) {
    int prv = (i - 1 + v.size()) % v.size();
    int cur = i % v.size();
    double c = cross(v[prv], v[cur]);
    if (EQ(c, 0))
      continue;
    else if (sign == 0) {
      if (c > 0)
        sign = 1;
      else
        sign = -1;
    } else {
      if (sign == -1 && c > 0)
        return false;
      else if (sign == 1 && c < 0)
        return false;
    }
  }
  return true;
}
struct Rec {
  vector<P> p;
};
// a1,a2を端点とする線分とb1,b2を端点とする線分の交差判定
int is_intersected_ls(P a1, P a2, P b1, P b2) {
  // 線分が平行な場合は重なっていないことにする
  if (abs(cross(a2 - a1, b2 - b1)) < EPS) {
    return 0;
  }
  return (cross(a2 - a1, b1 - a1) * cross(a2 - a1, b2 - a1) < EPS) &&
         (cross(b2 - b1, a1 - b1) * cross(b2 - b1, a2 - b1) < EPS);
}
// aとbの矩形が接しているかどうか(どちらかがどちからを含んでいるものもふくむ
bool isTouchRectangle(Rec &a, Rec &b) {
  // aの各頂点がbの中に存在しているかチェック
  for (int i = 0; i < 4; i++)
    if (isInPolygon(b.p, a.p[i]))
      return true;
  // 逆
  for (int i = 0; i < 4; i++)
    if (isInPolygon(a.p, b.p[i]))
      return true;
  // 各辺が他方のどれかの辺と接しているか
  for (int i = 0; i < 4; i++) {
    int curi = i;
    int prvi = (i - 1 + 4) % 4;
    for (int j = 0; j < 4; j++) {
      int curj = j;
      int prvj = (j - 1 + 4) % 4;
      if (is_intersected_ls(a.p[curi], a.p[prvi], b.p[curj], b.p[prvj]))
        return true;
    }
  }
  return false;
}
// a1,a2を端点とする線分とb1,b2を端点とする線分の交点計算
P intersection_ls(P a1, P a2, P b1, P b2) {
  P b = b2 - b1;
  double d1 = abs(cross(b, a1 - b1));
  double d2 = abs(cross(b, a2 - b1));
  double t = d1 / (d1 + d2);
  return a1 + (a2 - a1) * t;
}
// a1,a2を通る直線とb1,b2を通る直線の交差判定
int is_intersected_l(P a1, P a2, P b1, P b2) {
  return !EQ(cross(a1 - a2, b1 - b2), 0.0);
}
// a1,a2を通る直線とb1,b2を通る直線の交点計算
P intersection_l(P a1, P a2, P b1, P b2) {
  P a = a2 - a1;
  P b = b2 - b1;
  return a1 + a * cross(b, b1 - a1) / cross(b, a);
}
// 単位ベクトルを求める
P normalVector(P p) { return p / abs(p); }
// 法線ベクトルを求める
P unitVector(P a) { return P(-a.imag(), a.real()); }
// 単位法線ベクトルを求める
P unitNormalVector(P tmp) {
  P e = P(-tmp.imag(), tmp.real());
  e /= abs(e);
  return e;
}
// 座標の回転(座標pにある点を,半時計回りにa(ラジアン)回転)
P roundPoint(P p, double a) {
  return P(cos(a) * p.real() - sin(a) * p.imag(),
           sin(a) * p.real() + cos(a) * p.imag());
}
/*
円周と線分の交差判定
*/
bool isCircleCrossLine(P a, P b, P c, double r) {
  double d1 = abs(a - c);
  double d2 = abs(b - c);
  // 線分が中に含まれるとき、ここのコメントアウトをはずせばtrue(交差)となる
  // if(d1<r&&d2<r)
  //	return true;
  double d = distance_ls_p(a, b, c);
  return (EQ(d, r) || d < r);
}
// 三角形の内部に点があるかどうか
// 外積の正負がすべて同じなら内部に点あり
bool isInTriangle(P p1, P p2, P p3, P s) {
  P a = p1 - s;
  P b = p2 - s;
  P c = p3 - s;
  return ((cross(a, b) > 0 && cross(b, c) > 0 && cross(c, a) > 0) ||
          (cross(a, b) < 0 && cross(b, c) < 0 && cross(c, a) < 0));
}
// 矩形の中に点が存在するかどうか
bool isInRectangle(P p1, P p2, P p3, P p4, P s) {
  P a = p1 - s;
  P b = p2 - s;
  P c = p3 - s;
  P d = p4 - s;
  return ((cross(a, b) > 0 && cross(b, c) > 0 && cross(c, d) > 0 &&
           cross(d, a) > 0) ||
          (cross(a, b) < 0 && cross(b, c) < 0 && cross(c, d) < 0 &&
           cross(d, a) < 0));
}
// 三角形の面積を座標から計算
double calcAreaOfTriangle(P a, P b, P c) {
  return abs((b.real() - a.real()) * (c.imag() - a.imag()) -
             (c.real() - a.real()) * (b.imag() - a.imag())) /
         2;
}
// 与えられた円の範囲内に点が存在するかどうか
bool isContainingDot(P c, double r, P a) {
  return (((c.real() - a.real()) * (c.real() - a.real()) +
               (c.imag() - a.imag()) * (c.imag() - a.imag()) <
           r * r) ||
          EQ((c.real() - a.real()) * (c.real() - a.real()) +
                 (c.imag() - a.imag()) * (c.imag() - a.imag()),
             r * r));
}
// 多角形の面積公式
double calcPolygonArea(vector<P> p) {
  double sum = 0;
  for (int i = 0; i < p.size(); i++)
    sum += cross(p[i], p[(i + 1) % (p.size())]);
  return abs(sum / 2);
}
// 2ベクトル間の角度
// aからbへ左周りで何度か(0->2*PI)
double diffAngle(P a, P b) {
  double angle = atan2(cross(a, b), dot(a, b));
  if (angle < 0)
    return 2 * PI + angle;
  return angle;
}
// 2つのベクトルの重なっている部分の長さを返す
// もし重なっていなければ0を返す
double multipleLength(P a, P b, P c, P d) {
  Edge e1 = make_pair(a, b);
  Edge e2 = make_pair(c, d);
  // 平行であるかどうか
  if (!(is_parallel(e1.first, e2.first, e1.second, e2.second) &&
        is_parallel(e1.first, e1.second, e2.first, e2.second)))
    return 0;
  double dist = 0;
  // 両方乗っている
  if (EQ(distance_ls_p(e1.first, e1.second, e2.first), 0) &&
      EQ(distance_ls_p(e1.first, e1.second, e2.second), 0))
    dist = abs(e2.first - e2.second);
  else if (EQ(distance_ls_p(e2.first, e2.second, e1.first), 0) &&
           EQ(distance_ls_p(e2.first, e2.second, e1.second), 0))
    dist = abs(e1.first - e1.second);
  else if (EQ(distance_ls_p(e1.first, e1.second, e2.first), 0)) {
    // どちらが線上にあるか
    if (EQ(distance_ls_p(e2.first, e2.second, e1.first), 0))
      dist = abs(e1.first - e2.first);
    else
      dist = abs(e1.second - e2.first);
  } else if (EQ(distance_ls_p(e1.first, e1.second, e2.second), 0)) {
    if (EQ(distance_ls_p(e2.first, e2.second, e1.first), 0))
      dist = abs(e1.first - e2.second);
    else
      dist = abs(e1.second - e2.second);
  }
  return dist;
}
// 2点を通る半径rの円の中点を求める
pair<P, P> calcCircleCenterPoint(P dot1, P dot2, double r) {
  double v = abs(dot1 - dot2);
  double x = sqrt(r * r - (v / 2) * (v / 2));
  // 二組の単位法線ベクトル
  P hose[2];
  double x1 = -(dot1.imag() - dot2.imag());
  double y1 = (dot1.real() - dot2.real());
  hose[0] = P(x1, y1);
  double y2 = -y1;
  double x2 = -x1;
  hose[1] = P(x2, y2);
  double dd1 = abs(hose[0]);
  double dd2 = abs(hose[1]);
  hose[0] /= dd1;
  hose[0] *= x;
  hose[1] /= dd2;
  hose[1] *= x;
  P tmp = (dot1 + dot2);
  tmp /= 2;
  hose[0] += tmp;
  hose[1] += tmp;
  return make_pair(hose[0], hose[1]);
}
// 4線分が端点以外でクロスしているかどうかを判定
bool checkCross(const vector<Edge> &vec) {
  for (int i = 0; i < vec.size(); i++) {
    for (int j = i + 1; j < vec.size(); j++) {
      // 線分がクロスしているかどうか
      if (is_intersected_ls(vec[i].first, vec[i].second, vec[j].first,
                            vec[j].second)) {
        // している場合、端点以外でクロスしているなら、false
        P p = intersection_ls(vec[i].first, vec[i].second, vec[j].first,
                              vec[j].second);
        if (!(EQ(p, vec[i].first) || EQ(p, vec[i].second)))
          return false;
      }
    }
  }
  return true;
}
// 引き数で与えられた4つの点が矩形を作るどうかを判定
bool checkRec(const vector<P> &squ) {
  vector<int> v;
  for (int i = 0; i < squ.size(); i++)
    v.push_back(i);
  do {
    vector<Edge> ve;
    for (int i = 0; i < 4; i++)
      ve.push_back(make_pair(squ[v[i]], squ[v[(i + 1) % 4]]));
    // ここですべての線分がクロスするかどうかを計算
    if (checkCross(ve)) {
      // 線分の長さを確認
      if (EQ(abs(ve[0].first - ve[0].second), abs(ve[2].first - ve[2].second)))
        if (EQ(abs(ve[1].first - ve[1].second),
               abs(ve[3].first - ve[3].second)))
          // 直行
          if (is_orthogonal(ve[0].first, ve[0].second, ve[1].first,
                            ve[1].second))
            if (is_orthogonal(ve[2].first, ve[2].second, ve[3].first,
                              ve[3].second))
              return true;
    }
  } while (next_permutation(v.begin(), v.end()));
  return false;
}
// 引き数で与えられた4つの点が正方形を作るかどうかを判定
bool checkSqu(const vector<P> &squ) {
  vector<int> v;
  for (int i = 0; i < squ.size(); i++)
    v.push_back(i);
  do {
    vector<Edge> ve;
    for (int i = 0; i < 4; i++)
      ve.push_back(make_pair(squ[v[i]], squ[v[(i + 1) % 4]]));
    // ここですべての線分がクロスするかどうかを計算
    if (checkCross(ve)) {
      // 線分の長さを確認
      double d = abs(ve[0].first - ve[0].second);
      for (int i = 1; i < 4; i++) {
        double d2 = abs(ve[i].first - ve[i].second);
        if (!EQ(d, d2))
          return false;
      }
      // 直行確認
      if (is_orthogonal(ve[0].first, ve[0].second, ve[1].first, ve[1].second))
        if (is_orthogonal(ve[2].first, ve[2].second, ve[3].first, ve[3].second))
          return true;
    }
  } while (next_permutation(v.begin(), v.end()));
  return false;
}
// 二円の共通接線を構成する4直線を求める(二円はお互い接したりどちらかをふくんだりしない)
vector<pair<P, P>> calcCommonTangentialLine(P p1, double r1, P p2, double r2) {
  vector<pair<P, P>> res;
  if (r1 > r2) {
    swap(r1, r2);
    swap(p1, p2);
  }
  // 共通外接線
  {
    double d = abs(p1 - p2);
    double a = abs(r1 - r2);
    double b = sqrt(d * d - a * a);
    double sita = acos(b / d);
    P e = normalVector(roundPoint((roundPoint((p2 - p1), sita)), PI / 2));
    res.push_back(make_pair(e * r1 + p1, e * r2 + p2));
    P e2 = normalVector(roundPoint((roundPoint((p2 - p1), -sita)), -PI / 2));
    res.push_back(make_pair(e2 * r1 + p1, e2 * r2 + p2));
  }
  // 共通内接線
  {
    P cp = (r1 * p1 + r2 * p2) / (r1 + r2);
    double u = abs(cp - p1);
    double sita = acos(r1 / u);
    P e = normalVector(roundPoint(cp - p1, sita));
    res.push_back(make_pair(e * r1 + p1, -e * r2 + p2));
    P e2 = normalVector(roundPoint(cp - p1, -sita));
    res.push_back(make_pair(e2 * r1 + p1, -e2 * r2 + p2));
  }
  return res;
}
/*
  与えられた3点a,b,c,をa->b->cと進むとき
  a->bで時計方向に折れて,b->c
  a->bで半時計方向に折れて,b->c
  a->bで逆を向いてaを通り越してb->c
  a->bでそのままb->c
  a->bで逆を向いてb->c
  のどれであるかを判定
*/
int ccw(P a, P b, P c) {
  b -= a;
  c -= a;
  if (cross(b, c) > 0 && !EQ(cross(b, c), 0))
    return 1; // counter clockwise
  if (cross(b, c) < 0 && !EQ(cross(b, c), 0))
    return -1; // clockwise
  if (dot(b, c) < 0 && !EQ(dot(b, c), 0))
    return 2; // c-a-b on line
  if (!EQ(abs(b), abs(c)) && abs(b) < abs(c))
    return -2; // a-b-c on line
  return 0;
}
// 凸多角形の切断を行う
// lineのfirst側から見て右の多角形が返る
// 多角形は上が+y,右が+xの座標系で座標を時計周りに格納したvectorで表す
// lineは基本的にmakeDivisorで作成
vector<P> convex_cut(vector<P> polygon, pair<P, P> line) {
  vector<P> resPolygon;
  int n = polygon.size();
  for (int i = 0; i < n; i++) {
    P A = polygon[i];
    P B = polygon[(i + 1) % n];
    if (ccw(line.first, line.second, A) != -1)
      resPolygon.push_back(A);
    if (ccw(line.first, line.second, A) * ccw(line.first, line.second, B) < 0)
      resPolygon.push_back(intersection_l(A, B, line.first, line.second));
  }
  return resPolygon;
}

struct Point {
  P p;
  Point(P _p) { p = _p; }
  Point() {}
  bool operator<(const Point &op) const {
    if (EQ(p.real(), op.p.real())) {
      if (EQ(p.imag(), op.p.imag()))
        return false;
      else
        return p.imag() < op.p.imag();
    }
    return p.real() < op.p.real();
  }
};
struct edge {
  double dist;
  Point to;
};

const int MAX_N = 10000;
const int INF = 1000000000;
vector<edge> G[MAX_N];
double d[MAX_N];
vector<P> ps;
set<Point> nodes;
map<Point, int> m;
int idx;
int n;

typedef pair<double, int> pii;

double dijkstra() {
  for (int i = 0; i < idx; i++)
    d[i] = INF;
  priority_queue<pii> pq;
  pq.push(pii(0, m[Point(ps[0])]));
  // start
  d[m[Point(ps[0])]] = 0;
  while (pq.size()) {
    pii p = pq.top();
    pq.pop();
    double cost = p.first;
    int node = p.second;
    if (!EQ(d[node], cost) && d[node] < cost)
      continue;
    for (int i = 0; i < G[node].size(); i++) {
      edge &e = G[node][i];
      if (!EQ(d[m[e.to]], cost + e.dist) && d[m[e.to]] > cost + e.dist) {
        d[m[e.to]] = cost + e.dist;
        pq.push(pii(d[m[e.to]], m[e.to]));
      }
    }
  }
  // ゴールへの最短距離
  return d[m[Point(ps[n - 1])]];
}

int main() {
  while (cin >> n && n) {
    double vw, vc;
    idx = 0;
    ps.clear();
    m.clear();
    nodes.clear();
    cin >> vw >> vc;
    for (int i = 0; i < n; i++) {
      double x, y;
      cin >> x >> y;
      ps.push_back(P(x, y));
    }
    for (int i = 0; i < n; i++) {
      if (m.count(Point(ps[i])) == 0) {
        nodes.insert(Point(ps[i]));
        m[Point(ps[i])] = idx++;
      }
      // 谷の端点の場合、左右に伸ばす
      // 右　
      if ((i + 1 < n && !EQ(ps[i + 1].imag(), ps[i].imag()) &&
           (ps[i + 1].imag() > ps[i].imag()))) {
        for (int j = i + 1; j < n - 1; j++) {
          P a = ps[j];
          P b = ps[j + 1];
          // 線分a--bとy=ps[i].imag()が交差するか？
          // 交差するなら,nodeを追加
          if (is_intersected_ls(a, b, P(-1000000, ps[i].imag()),
                                P(1000000, ps[i].imag()))) {
            P cp = intersection_ls(a, b, P(-1000000, ps[i].imag()),
                                   P(1000000, ps[i].imag()));
            if (m.count(Point(cp)) == 0) {
              m[Point(cp)] = idx++;
              nodes.insert(Point(cp));
            }
            break;
          }
          // 平行かつy座標が同じ線分にぶつかった場合
          else if (EQ(ps[i].imag(), ps[j].imag()) &&
                   EQ(ps[j].imag(), ps[j + 1].imag()))
            break;
        }
      }
      // 左
      if (i - 1 >= 0 && !EQ(ps[i - 1].imag(), ps[i].imag()) &&
          (ps[i - 1].imag() > ps[i].imag())) {
        for (int j = i - 1; j > 0; j--) {
          P a = ps[j];
          P b = ps[j - 1];
          // 線分a--bとy=ps[i].imag()が交差するか？
          // 交差するなら,nodeを追加
          if (is_intersected_ls(a, b, P(-1000000, ps[i].imag()),
                                P(1000000, ps[i].imag()))) {
            P cp = intersection_ls(a, b, P(-1000000, ps[i].imag()),
                                   P(1000000, ps[i].imag()));
            if (m.count(Point(cp)) == 0) {
              nodes.insert(Point(cp));
              m[Point(cp)] = idx++;
            }
            break;
          } else if (EQ(ps[i].imag(), ps[j].imag()) &&
                     EQ(ps[j].imag(), ps[j - 1].imag()))
            break;
        }
      }
    }
    // 交点の位置でソートしておき
    // 一つ隣の交点は通行可能
    // その他同じy座標を持つところにも通行可能
    for (set<Point>::iterator it = nodes.begin(); it != nodes.end(); it++) {
      // cout<<it->p<<endl;
      //  歩いていけるところにエッジを結ぶ
      set<Point>::iterator nxt = it;
      nxt++;
      if (nxt != nodes.end()) {
        edge e;
        // 隣接地点へ歩いて渡る
        e.dist = abs((it->p) - (nxt->p)) / vw;
        e.to = *it;
        G[m[*nxt]].push_back(e);
        e.to = *nxt;
        G[m[*it]].push_back(e);
      }
      // 同じy座標のノードを追加
      // x座標で隣接するものを使用
      int ang = -1;
      for (set<Point>::iterator iit = it; iit != nodes.end(); iit++) {
        // 最初は一つ進めておく
        if (iit == it)
          iit++;
        if (iit == nodes.end())
          break;
        if (EQ(iit->p.imag(), it->p.imag())) {
          set<Point>::iterator itnxt = it;
          itnxt++;
          // 隣は歩いていけるのでx
          if (itnxt != iit) {
            if (ang == 0)
              continue;
            edge e;
            e.dist = abs((iit->p) - (it->p)) / vc;
            e.to = *iit;
            G[m[*it]].push_back(e);
          }
          break;
        }
        if (ang == -1) {
          if (iit->p.imag() > it->p.imag())
            ang = 1; // zouka
          else
            ang = 0; // heru
        }
      }
      // ang=-1;
      // for(set<Point>::iterator iit=it;;iit--){
      //  	if(iit==nodes.begin())break;
      // 	// 最初は一つ進めておく
      // 	if(iit==it)iit--;
      // 	// y座標が一致
      // 	if(EQ(iit->p.imag(),it->p.imag())){
      // 	  set<Point>::iterator itnxt=it;itnxt--;
      // 	  // 隣は歩いていけるのでx
      // 	  if(itnxt!=iit){
      // 	    if(ang==0)continue;
      // 	    edge e;
      // 	    e.dist=abs((iit->p)-(it->p))/vc;
      // 	    e.to=*iit;
      // 	    G[m[*it]].push_back(e);
      // 	  }
      // 	  break;
      // 	}
      // 	if(ang==-1){
      // 	  if(iit->p.imag()>it->p.imag())ang=0;//zouka
      // 	  else ang=1;//heru
      // 	}
      // 	if(iit==nodes.begin())break;
      // }
    }
    double res = dijkstra();
    printf("%.10f\\n", res);
    for (int i = 0; i < idx; i++)
      G[i].clear();
  }

  return 0;
}

Error: TLE

Fixed submission:

#include <algorithm>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <iterator>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

#define EPS (1e-10)
#define EQ(a, b) (abs((a) - (b)) < EPS)
#define EQV(a, b) (EQ((a).real(), (b).real()) && EQ((a).imag(), (b).imag()))

typedef complex<double> P;
typedef pair<P, P> Edge;
typedef long long ll;

const double PI = 4 * atan(1.0);
const int MAX_SIZE = 10000;

// 内積
double dot(P a, P b) { return (a.real() * b.real() + a.imag() * b.imag()); }
// 外積
double cross(P a, P b) { return (a.real() * b.imag() - a.imag() * b.real()); }
// 点cが直線ab上にあるかないか
int is_point_on_line(P a, P b, P c) { return EQ(cross(b - a, c - a), 0.0); }
// 2直線の直行判定
int is_orthogonal(P a1, P a2, P b1, P b2) {
  return EQ(dot(a1 - a2, b1 - b2), 0.0);
}
// 2直線の平行判定
int is_parallel(P a1, P a2, P b1, P b2) {
  return EQ(cross(a1 - a2, b1 - b2), 0.0);
}
// 点a,bを通る直線と点cの間の距離
double distance_l_p(P a, P b, P c) {
  return abs(cross(b - a, c - a)) / abs(b - a);
}
// 点a,bを端点とする線分と点cとの距離
double distance_ls_p(P a, P b, P c) {
  if (dot(b - a, c - a) < EPS)
    return abs(c - a);
  if (dot(a - b, c - b) < EPS)
    return abs(c - b);
  return abs(cross(b - a, c - a)) / abs(b - a);
}
// 点が多角形の中に存在するかどうか
bool isInPolygon(vector<P> &points, P s) {
  if (points.size() == 1)
    return false;
  vector<P> v;
  for (int i = 0; i < (int)points.size(); i++)
    v.push_back(points[i] - s);
  int sign = 0;
  for (int i = 1; i <= (int)v.size(); i++) {
    int prv = (i - 1 + v.size()) % v.size();
    int cur = i % v.size();
    double c = cross(v[prv], v[cur]);
    if (EQ(c, 0))
      continue;
    else if (sign == 0) {
      if (c > 0)
        sign = 1;
      else
        sign = -1;
    } else {
      if (sign == -1 && c > 0)
        return false;
      else if (sign == 1 && c < 0)
        return false;
    }
  }
  return true;
}
struct Rec {
  vector<P> p;
};
// a1,a2を端点とする線分とb1,b2を端点とする線分の交差判定
int is_intersected_ls(P a1, P a2, P b1, P b2) {
  // 線分が平行な場合は重なっていないことにする
  if (abs(cross(a2 - a1, b2 - b1)) < EPS) {
    return 0;
  }
  return (cross(a2 - a1, b1 - a1) * cross(a2 - a1, b2 - a1) < EPS) &&
         (cross(b2 - b1, a1 - b1) * cross(b2 - b1, a2 - b1) < EPS);
}
// aとbの矩形が接しているかどうか(どちらかがどちからを含んでいるものもふくむ
bool isTouchRectangle(Rec &a, Rec &b) {
  // aの各頂点がbの中に存在しているかチェック
  for (int i = 0; i < 4; i++)
    if (isInPolygon(b.p, a.p[i]))
      return true;
  // 逆
  for (int i = 0; i < 4; i++)
    if (isInPolygon(a.p, b.p[i]))
      return true;
  // 各辺が他方のどれかの辺と接しているか
  for (int i = 0; i < 4; i++) {
    int curi = i;
    int prvi = (i - 1 + 4) % 4;
    for (int j = 0; j < 4; j++) {
      int curj = j;
      int prvj = (j - 1 + 4) % 4;
      if (is_intersected_ls(a.p[curi], a.p[prvi], b.p[curj], b.p[prvj]))
        return true;
    }
  }
  return false;
}
// a1,a2を端点とする線分とb1,b2を端点とする線分の交点計算
P intersection_ls(P a1, P a2, P b1, P b2) {
  P b = b2 - b1;
  double d1 = abs(cross(b, a1 - b1));
  double d2 = abs(cross(b, a2 - b1));
  double t = d1 / (d1 + d2);

  return a1 + (a2 - a1) * t;
}
// a1,a2を通る直線とb1,b2を通る直線の交差判定
int is_intersected_l(P a1, P a2, P b1, P b2) {
  return !EQ(cross(a1 - a2, b1 - b2), 0.0);
}
// a1,a2を通る直線とb1,b2を通る直線の交点計算
P intersection_l(P a1, P a2, P b1, P b2) {
  P a = a2 - a1;
  P b = b2 - b1;
  return a1 + a * cross(b, b1 - a1) / cross(b, a);
}
// 単位ベクトルを求める
P normalVector(P p) { return p / abs(p); }
// 法線ベクトルを求める
P unitVector(P a) { return P(-a.imag(), a.real()); }
// 単位法線ベクトルを求める
P unitNormalVector(P tmp) {
  P e = P(-tmp.imag(), tmp.real());
  e /= abs(e);
  return e;
}
// 座標の回転(座標pにある点を,半時計回りにa(ラジアン)回転)
P roundPoint(P p, double a) {
  return P(cos(a) * p.real() - sin(a) * p.imag(),
           sin(a) * p.real() + cos(a) * p.imag());
}
/*
円周と線分の交差判定
*/
bool isCircleCrossLine(P a, P b, P c, double r) {
  double d1 = abs(a - c);
  double d2 = abs(b - c);
  // 線分が中に含まれるとき、ここのコメントアウトをはずせばtrue(交差)となる
  // if(d1<r&&d2<r)
  //	return true;
  double d = distance_ls_p(a, b, c);
  return (EQ(d, r) || d < r);
}
// 三角形の内部に点があるかどうか
// 外積の正負がすべて同じなら内部に点あり
bool isInTriangle(P p1, P p2, P p3, P s) {
  P a = p1 - s;
  P b = p2 - s;
  P c = p3 - s;
  return ((cross(a, b) > 0 && cross(b, c) > 0 && cross(c, a) > 0) ||
          (cross(a, b) < 0 && cross(b, c) < 0 && cross(c, a) < 0));
}
// 矩形の中に点が存在するかどうか
bool isInRectangle(P p1, P p2, P p3, P p4, P s) {
  P a = p1 - s;
  P b = p2 - s;
  P c = p3 - s;
  P d = p4 - s;
  return ((cross(a, b) > 0 && cross(b, c) > 0 && cross(c, d) > 0 &&
           cross(d, a) > 0) ||
          (cross(a, b) < 0 && cross(b, c) < 0 && cross(c, d) < 0 &&
           cross(d, a) < 0));
}
// 三角形の面積を座標から計算
double calcAreaOfTriangle(P a, P b, P c) {
  return abs((b.real() - a.real()) * (c.imag() - a.imag()) -
             (c.real() - a.real()) * (b.imag() - a.imag())) /
         2;
}
// 与えられた円の範囲内に点が存在するかどうか
bool isContainingDot(P c, double r, P a) {
  return (((c.real() - a.real()) * (c.real() - a.real()) +
               (c.imag() - a.imag()) * (c.imag() - a.imag()) <
           r * r) ||
          EQ((c.real() - a.real()) * (c.real() - a.real()) +
                 (c.imag() - a.imag()) * (c.imag() - a.imag()),
             r * r));
}
// 多角形の面積公式
double calcPolygonArea(vector<P> p) {
  double sum = 0;
  for (int i = 0; i < p.size(); i++)
    sum += cross(p[i], p[(i + 1) % (p.size())]);
  return abs(sum / 2);
}
// 2ベクトル間の角度
// aからbへ左周りで何度か(0->2*PI)
double diffAngle(P a, P b) {
  double angle = atan2(cross(a, b), dot(a, b));
  if (angle < 0)
    return 2 * PI + angle;
  return angle;
}
// 2つのベクトルの重なっている部分の長さを返す
// もし重なっていなければ0を返す
double multipleLength(P a, P b, P c, P d) {
  Edge e1 = make_pair(a, b);
  Edge e2 = make_pair(c, d);
  // 平行であるかどうか
  if (!(is_parallel(e1.first, e2.first, e1.second, e2.second) &&
        is_parallel(e1.first, e1.second, e2.first, e2.second)))
    return 0;
  double dist = 0;
  // 両方乗っている
  if (EQ(distance_ls_p(e1.first, e1.second, e2.first), 0) &&
      EQ(distance_ls_p(e1.first, e1.second, e2.second), 0))
    dist = abs(e2.first - e2.second);
  else if (EQ(distance_ls_p(e2.first, e2.second, e1.first), 0) &&
           EQ(distance_ls_p(e2.first, e2.second, e1.second), 0))
    dist = abs(e1.first - e1.second);
  else if (EQ(distance_ls_p(e1.first, e1.second, e2.first), 0)) {
    // どちらが線上にあるか
    if (EQ(distance_ls_p(e2.first, e2.second, e1.first), 0))
      dist = abs(e1.first - e2.first);
    else
      dist = abs(e1.second - e2.first);
  } else if (EQ(distance_ls_p(e1.first, e1.second, e2.second), 0)) {
    if (EQ(distance_ls_p(e2.first, e2.second, e1.first), 0))
      dist = abs(e1.first - e2.second);
    else
      dist = abs(e1.second - e2.second);
  }
  return dist;
}
// 2点を通る半径rの円の中点を求める
pair<P, P> calcCircleCenterPoint(P dot1, P dot2, double r) {
  double v = abs(dot1 - dot2);
  double x = sqrt(r * r - (v / 2) * (v / 2));
  // 二組の単位法線ベクトル
  P hose[2];
  double x1 = -(dot1.imag() - dot2.imag());
  double y1 = (dot1.real() - dot2.real());
  hose[0] = P(x1, y1);
  double y2 = -y1;
  double x2 = -x1;
  hose[1] = P(x2, y2);
  double dd1 = abs(hose[0]);
  double dd2 = abs(hose[1]);
  hose[0] /= dd1;
  hose[0] *= x;
  hose[1] /= dd2;
  hose[1] *= x;
  P tmp = (dot1 + dot2);
  tmp /= 2;
  hose[0] += tmp;
  hose[1] += tmp;
  return make_pair(hose[0], hose[1]);
}
// 4線分が端点以外でクロスしているかどうかを判定
bool checkCross(const vector<Edge> &vec) {
  for (int i = 0; i < vec.size(); i++) {
    for (int j = i + 1; j < vec.size(); j++) {
      // 線分がクロスしているかどうか
      if (is_intersected_ls(vec[i].first, vec[i].second, vec[j].first,
                            vec[j].second)) {
        // している場合、端点以外でクロスしているなら、false
        P p = intersection_ls(vec[i].first, vec[i].second, vec[j].first,
                              vec[j].second);
        if (!(EQ(p, vec[i].first) || EQ(p, vec[i].second)))
          return false;
      }
    }
  }
  return true;
}
// 引き数で与えられた4つの点が矩形を作るどうかを判定
bool checkRec(const vector<P> &squ) {
  vector<int> v;
  for (int i = 0; i < squ.size(); i++)
    v.push_back(i);
  do {
    vector<Edge> ve;
    for (int i = 0; i < 4; i++)
      ve.push_back(make_pair(squ[v[i]], squ[v[(i + 1) % 4]]));
    // ここですべての線分がクロスするかどうかを計算
    if (checkCross(ve)) {
      // 線分の長さを確認
      if (EQ(abs(ve[0].first - ve[0].second), abs(ve[2].first - ve[2].second)))
        if (EQ(abs(ve[1].first - ve[1].second),
               abs(ve[3].first - ve[3].second)))
          // 直行
          if (is_orthogonal(ve[0].first, ve[0].second, ve[1].first,
                            ve[1].second))
            if (is_orthogonal(ve[2].first, ve[2].second, ve[3].first,
                              ve[3].second))
              return true;
    }
  } while (next_permutation(v.begin(), v.end()));
  return false;
}
// 引き数で与えられた4つの点が正方形を作るかどうかを判定
bool checkSqu(const vector<P> &squ) {
  vector<int> v;
  for (int i = 0; i < squ.size(); i++)
    v.push_back(i);
  do {
    vector<Edge> ve;
    for (int i = 0; i < 4; i++)
      ve.push_back(make_pair(squ[v[i]], squ[v[(i + 1) % 4]]));
    // ここですべての線分がクロスするかどうかを計算
    if (checkCross(ve)) {
      // 線分の長さを確認
      double d = abs(ve[0].first - ve[0].second);
      for (int i = 1; i < 4; i++) {
        double d2 = abs(ve[i].first - ve[i].second);
        if (!EQ(d, d2))
          return false;
      }
      // 直行確認
      if (is_orthogonal(ve[0].first, ve[0].second, ve[1].first, ve[1].second))
        if (is_orthogonal(ve[2].first, ve[2].second, ve[3].first, ve[3].second))
          return true;
    }
  } while (next_permutation(v.begin(), v.end()));
  return false;
}
// 二円の共通接線を構成する4直線を求める(二円はお互い接したりどちらかをふくんだりしない)
vector<pair<P, P>> calcCommonTangentialLine(P p1, double r1, P p2, double r2) {
  vector<pair<P, P>> res;
  if (r1 > r2) {
    swap(r1, r2);
    swap(p1, p2);
  }
  // 共通外接線
  {
    double d = abs(p1 - p2);
    double a = abs(r1 - r2);
    double b = sqrt(d * d - a * a);
    double sita = acos(b / d);
    P e = normalVector(roundPoint((roundPoint((p2 - p1), sita)), PI / 2));
    res.push_back(make_pair(e * r1 + p1, e * r2 + p2));
    P e2 = normalVector(roundPoint((roundPoint((p2 - p1), -sita)), -PI / 2));
    res.push_back(make_pair(e2 * r1 + p1, e2 * r2 + p2));
  }
  // 共通内接線
  {
    P cp = (r1 * p1 + r2 * p2) / (r1 + r2);
    double u = abs(cp - p1);
    double sita = acos(r1 / u);
    P e = normalVector(roundPoint(cp - p1, sita));
    res.push_back(make_pair(e * r1 + p1, -e * r2 + p2));
    P e2 = normalVector(roundPoint(cp - p1, -sita));
    res.push_back(make_pair(e2 * r1 + p1, -e2 * r2 + p2));
  }
  return res;
}
/*
  与えられた3点a,b,c,をa->b->cと進むとき
  a->bで時計方向に折れて,b->c
  a->bで半時計方向に折れて,b->c
  a->bで逆を向いてaを通り越してb->c
  a->bでそのままb->c
  a->bで逆を向いてb->c
  のどれであるかを判定
*/
int ccw(P a, P b, P c) {
  b -= a;
  c -= a;
  if (cross(b, c) > 0 && !EQ(cross(b, c), 0))
    return 1; // counter clockwise
  if (cross(b, c) < 0 && !EQ(cross(b, c), 0))
    return -1; // clockwise
  if (dot(b, c) < 0 && !EQ(dot(b, c), 0))
    return 2; // c-a-b on line
  if (!EQ(abs(b), abs(c)) && abs(b) < abs(c))
    return -2; // a-b-c on line
  return 0;
}
// 凸多角形の切断を行う
// lineのfirst側から見て右の多角形が返る
// 多角形は上が+y,右が+xの座標系で座標を時計周りに格納したvectorで表す
// lineは基本的にmakeDivisorで作成
vector<P> convex_cut(vector<P> polygon, pair<P, P> line) {
  vector<P> resPolygon;
  int n = polygon.size();
  for (int i = 0; i < n; i++) {
    P A = polygon[i];
    P B = polygon[(i + 1) % n];
    if (ccw(line.first, line.second, A) != -1)
      resPolygon.push_back(A);
    if (ccw(line.first, line.second, A) * ccw(line.first, line.second, B) < 0)
      resPolygon.push_back(intersection_l(A, B, line.first, line.second));
  }
  return resPolygon;
}

struct Point {
  P p;
  Point(P _p) { p = _p; }
  Point() {}
  bool operator<(const Point &op) const {
    if (EQ(p.real(), op.p.real())) {
      if (EQ(p.imag(), op.p.imag()))
        return false;
      else
        return p.imag() < op.p.imag();
    }
    return p.real() < op.p.real();
  }
};
struct edge {
  double dist;
  Point to;
};

const int MAX_N = 1000001;
const int INF = 1000000000;
vector<edge> G[MAX_N];
double d[MAX_N];
vector<P> ps;
set<Point> nodes;
map<Point, int> m;
int idx;
int n;

typedef pair<double, int> pii;

double dijkstra() {
  for (int i = 0; i < idx; i++)
    d[i] = INF;
  priority_queue<pii> pq;
  pq.push(pii(0, m[Point(ps[0])]));
  // start
  d[m[Point(ps[0])]] = 0;
  while (pq.size()) {
    pii p = pq.top();
    pq.pop();
    double cost = p.first;
    int node = p.second;
    if (!EQ(d[node], cost) && d[node] < cost)
      continue;
    for (int i = 0; i < G[node].size(); i++) {
      edge &e = G[node][i];
      if (d[m[e.to]] > cost + e.dist) {
        d[m[e.to]] = cost + e.dist;
        pq.push(pii(d[m[e.to]], m[e.to]));
      }
    }
  }
  // ゴールへの最短距離
  return d[m[Point(ps[n - 1])]];
}

int main() {
  while (cin >> n && n) {
    double vw, vc;
    idx = 0;
    ps.clear();
    m.clear();
    nodes.clear();
    cin >> vw >> vc;
    for (int i = 0; i < n; i++) {
      double x, y;
      cin >> x >> y;
      ps.push_back(P(x, y));
    }
    for (int i = 0; i < n; i++) {
      for (int j = 1; j < n; j++) {
        P a = ps[j - 1];
        P b = ps[j];
        // 線分a--bとy=ps[i].imag()が交差するか？
        if (is_intersected_ls(a, b, P(-1000000, ps[i].imag()),
                              P(1000000, ps[i].imag()))) {
          P cp = intersection_ls(a, b, P(-1000000, ps[i].imag()),
                                 P(1000000, ps[i].imag()));
          nodes.insert(Point(cp));
          m[Point(cp)] = idx++;
        }
      }
      nodes.insert(Point(ps[i]));
      m[Point(ps[i])] = idx++;
    }
    // 交点の位置でソートしておき
    // 一つ隣の交点は通行可能
    // その他同じy座標を持つところにも通行可能
    for (set<Point>::iterator it = nodes.begin(); it != nodes.end(); it++) {
      // 歩いていけるところにエッジを結ぶ
      set<Point>::iterator nxt = it;
      nxt++;
      if (nxt != nodes.end()) {
        edge e;
        // 隣接地点へ歩いて渡る
        e.dist = abs((it->p) - (nxt->p)) / vw;
        e.to = *it;
        G[m[*nxt]].push_back(e);
        e.to = *nxt;
        G[m[*it]].push_back(e);
      }
      // 同じy座標のノードを追加
      // x座標で隣接するものを使用
      for (set<Point>::iterator iit = it; iit != nodes.end(); iit++) {
        // 最初は一つ進めておく
        if (iit == it)
          iit++;
        if (iit == nodes.end())
          break;
        if (EQ(iit->p.imag(), it->p.imag())) {
          set<Point>::iterator itnxt = it;
          itnxt++;
          // 隣は歩いていけるのでx
          if (itnxt != iit) {
            edge e;
            e.dist = abs((iit->p) - (it->p)) / vc;
            e.to = *iit;
            G[m[*it]].push_back(e);
          }
          break;
        }
      }
      for (set<Point>::iterator iit = it;; iit--) {
        if (iit == nodes.begin())
          break;
        // 最初は一つ進めておく
        if (iit == it)
          iit--;
        // y座標が一致
        if (EQ(iit->p.imag(), it->p.imag())) {
          set<Point>::iterator itnxt = it;
          itnxt--;
          // 隣は歩いていけるのでx
          if (itnxt != iit) {
            edge e;
            e.dist = abs((iit->p) - (it->p)) / vc;
            e.to = *iit;
            G[m[*it]].push_back(e);
          }
          break;
        }
        if (iit == nodes.begin())
          break;
      }
    }
    double res = dijkstra();
    printf("%.10f\\n", res);
    for (int i = 0; i < idx; i++)
      G[i].clear();
  }

  return 0;
}