Problem:
ねこまっしぐら２

あるところに大きな古いお屋敷があり、１匹のねこが住み着いていました。図のように、お屋敷は上空から見ると凸多角形になっており、まっすぐな壁で囲まれたいくつかの部屋で造られています。１枚の壁はその両端にある柱によって支えられています。お屋敷はとても古いため、どの壁にもねこが通ることができるくらいの穴が１つ空いています。ねこは壁の穴を通ってお屋敷の部屋と部屋または部屋と外を行き来することができます。

お屋敷のご主人は、ねこに餌をあげるために、口笛を吹いてねこをお屋敷の外へ呼び出します。ねこはとても賢く、ご主人が口笛を吹くと、「最良の選択」でお屋敷の外へ抜け出します。つまり、最も少ない回数だけ穴を通って外へ出ます。

ねこはとても気まぐれで、どの部屋にいるか分かりません。そのため、ねこがお屋敷の外へ出るのにかかる時間は日によって異なり、ご主人はどれだけ待てばよいかわからず困っていました。ある時ご主人は、ねこが穴を通り抜けるときに、とても時間がかかっていることに気が付きました。ということは、ねこが外に出るのにかかる時間は穴を通る回数によって決まることになります。ご主人は、ねこが「最良の選択」をした場合の穴を通る回数の最大値が分かれば、ねこがどの部屋にいたとしても、最大どれだけ待てばよいか分かるのではないかと考えました。ご主人はお屋敷の間取りを知っていますが、お屋敷はとても大きく、自分では計算することができません...。

お屋敷の間取りを読み込み、ねこが「最良の選択」をした場合、外に出るまでに通る穴の数の最大値を
出力するプログラムを作成して下さい。

入力

入力は複数のデータセットからなる。入力の終わりはゼロ２つの行で示される。各データセットは以下の形式で与えられる。

C W
x1 y1
x2 y2
:
xC yC
s1 t1
s2 t2
:
sW tW

各行で与えられる数値は１つの空白で区切られている。

１行目に柱の数 C (3 ≤ C ≤ 100) と壁の数 W (3 ≤ W ≤ 300) が与えられる。続く C 行に柱の座標が与えられる。xi (-1000 ≤ xi ≤ 1000) は i 番目の柱の x 座標、yi (-1000 ≤ yi ≤ 1000) は i 番目の柱の y 座標をそれぞれ示す整数である。柱にはそれぞれ 1 から C までの番号が割り当てられている。 続く W 行に壁の情報が与えられる。

si (1 ≤ si ≤ C)、ti (1 ≤ ti ≤ C) は壁の両端を支える柱の番号を示す。

入力は以下の条件を満たすと考えてよい。

異なる柱が同じ位置を占めることはない。

異なる壁が重なったり、柱以外で交差することはない。

１つの柱は２つ以上の壁を支えている。

壁の長さは 0 より大きい。

柱は壁の両端だけにある。つまり、柱が壁の途中にあることはない。

壁は異なる２つの部屋、あるいは部屋と外とを仕切る。

任意の異なる２つの柱を選んだとき、互いの柱には壁をたどって到達できる。

データセットの数は 50 を超えない。

出力

データセットごとに、ねこが「最良の選択」をした場合、外に出るまでに通る穴の数の最大値を１行に出力する。

入力例

4 4
0 0
1 0
1 1
0 1
1 2
1 4
2 3
3 4
12 22
2 0
4 0
8 0
4 2
6 2
8 2
2 4
4 4
6 4
0 6
8 6
0 8
1 2
2 3
1 4
1 7
1 10
2 4
2 5
3 5
3 6
4 5
4 8
5 6
5 9
6 9
6 11
7 10
7 8
8 9
9 11
10 11
10 12
11 12
0 0

出力例

1
3

２つ目のデータセットが、冒頭の図に示したお屋敷の間取りに対応する。図のように、薄く色が塗られた部屋にねこがいるときは、「最良の選択」で外に出るまでに通り抜ける穴の数は３つである。それ以外の部屋にねこがいるときは、２つ以下で外に出られる。したがって、ねこが「最良の選択」をしたとき、外に出るまでに通り抜ける穴の数の最大値は 3 になる。

Solution in C++11 (judge verdict: Accepted)

//
// [not yet accepted]
//
#include <iostream>
#include <vector>
#include <fstream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <map>
#include <queue>
#include <set>
#include <functional>
#include <ctime>
#include <numeric>
#include <unordered_set>
#include <unordered_map>

using namespace std;

#define fst first
#define snd second
#define all(c) ((c).begin()), ((c).end())
#define TEST(x,a) { auto y=(x); if (sign(y-a)) { cout << "line " << __LINE__  << #x << " = " << y << " != " << a << endl; exit(-1); } }

const double EPS = 1e-8;
int sign(double x) {
  if (x < -EPS) return -1;
  if (x > +EPS) return +1;
  return 0;
}
struct point {
  typedef double T;
  T x, y; 
  point &operator+=(point p) { x += p.x; y += p.y; return *this; }
  point &operator-=(point p) { x -= p.x; y -= p.y; return *this; }
  point &operator*=(T a)     { x *= a;   y *= a;   return *this; }
  point &operator/=(T a)     { return *this *= (1.0/a); }
  point operator-() const    { return {-x, -y}; }
  bool operator<(point p) const { 
    int s = sign(x - p.x);
    return s ? s < 0 : sign(y - p.y) < 0;
  }
};
bool operator==(point p, point q) { return !(p < q) && !(q < p); }
point operator+(point p, point q) { return p += q; }
point operator-(point p, point q) { return p -= q; }
point operator*(point::T a, point p) { return p *= a; }
point operator*(point p, point::T a) { return p *= a; }
point operator/(point p, point::T a) { return p /= a; }
point::T dot(point p, point q) { return p.x*q.x+p.y*q.y; }
point::T cross(point p, point q) { return p.x*q.y-p.y*q.x; } // left turn > 0
point::T norm2(point p) { return dot(p,p); }
point orth(point p) { return {-p.y, p.x}; }
point::T norm(point p) { return sqrt(dot(p,p)); }
point::T arg(point p) { return atan2(p.y, p.x); }

struct line { point p, q; };
bool operator==(line l, line m) {
  return !sign(cross(l.p-l.q,m.p-m.q)) && !sign(cross(l.p-l.q,m.p-l.p));
}

struct segment { point p, q; };
bool operator==(segment l, line m) {
  return (l.p==m.p && l.q==m.q) || (l.p==m.q && l.q==m.p); // do not consider the direction
}
struct circle { point p; point::T r; };
bool operator==(circle c, circle d) { return c.p == d.p && !sign(c.r - d.r); }

typedef vector<point> polygon;

struct polar_angle {
  const point o;
  const int s; // +1 for ccw, -1 for cw
  polar_angle(point p = {0,0}, int s = +1) : o(p), s(s) { }
  int quad(point p) const {
    for (int i = 1; i <= 4; ++i, swap(p.x = -p.x, p.y))
      if (p.x > 0 && p.y >= 0) return i;
    return 0;
  }
  bool operator()(point p, point q) const {
    p = p - o; q = q - o;
    if (quad(p) != quad(q)) return s*quad(p) < s*quad(q);
    if (cross(p, q)) return s*cross(p, q) > 0;
    return norm2(p) < norm2(q); // closer first
  }
};

vector<point> intersect(segment s, segment t) {
  auto a = cross(s.q - s.p, t.q - t.p);
  auto b = cross(t.p - s.p, t.q - t.p); 
  auto c = cross(s.q - s.p, s.p - t.p);
  if (a < 0) { a = -a; b = -b; c = -c; }
  if (sign(b) < 0 || sign(a-b) < 0 ||
      sign(c) < 0 || sign(a-c) < 0) return {};      // disjoint
  if (sign(a) != 0) return {s.p + b/a*(s.q - s.p)}; // properly crossing
  vector<point> ps;                                 // same line
  auto insert_if_possible = [&](point p) {
    for (auto q: ps) if (sign(dot(p-q, p-q)) == 0) return;
    ps.push_back(p);
  };
  if (sign(dot(s.p-t.p, s.q-t.p)) <= 0) insert_if_possible(t.p);
  if (sign(dot(s.p-t.q, s.q-t.q)) <= 0) insert_if_possible(t.q);
  if (sign(dot(t.p-s.p, t.q-s.p)) <= 0) insert_if_possible(s.p);
  if (sign(dot(t.p-s.q, t.q-s.q)) <= 0) insert_if_possible(s.q);
  return ps;
}

struct arrangement {
  struct edge {
    int src, dst;
    point::T weight;
    size_t id, rev;
  };
  int n;
  vector<point> ps; // ps[id[p]] = p, id[ps[k]] = k
  map<point,int> id; 
  vector<vector<edge>> adj;

  arrangement(vector<segment> ss) : n(0) {
    vector<vector<pair<point::T, int>>> group(ss.size());
    auto append = [&](int i, point p) {
      if (!id.count(p)) { id[p] = n++; ps.push_back(p); }
      group[i].push_back({norm(ss[i].p - p), id[p]});
    };
    for (int i = 0; i < ss.size(); ++i) {
      append(i, ss[i].p); append(i, ss[i].q);
      for (int j = 0; j < i; ++j) {
        for (point p: intersect(ss[i], ss[j])) {
          append(i, p); append(j, p);
        }
      }
    }
    adj.resize(n);
    for (auto &vs: group) {
      sort(all(vs));
      for (int i = 0; i+1 < vs.size(); ++i) {
        auto u = vs[i].snd, v = vs[i+1].snd;
        if (u == v) continue;
        auto len = vs[i+1].fst - vs[i].fst;
        adj[u].push_back({u, v, len});
        adj[v].push_back({v, u, len});
      }
    }
    // remove duplicates and orient edges
    vector<unordered_map<int, int>> idx(n);
    for (int u = 0; u < n; ++u) {
      auto eq = [&](edge e, edge f) { return e.dst == f.dst; };
      auto lt = [&](edge e, edge f) { return e.dst <  f.dst; };
      sort(all(adj[u]), lt);
      adj[u].erase(unique(all(adj[u]), eq), adj[u].end());
      sort(all(adj[u]), [&](edge e, edge f) {
        return arg(ps[e.dst] - ps[e.src]) > arg(ps[f.dst] - ps[f.src]);
      });
      for (int i = 0; i < adj[u].size(); ++i) {
        adj[u][i].id = i;
        int v = adj[u][i].dst;
        idx[u][v] = i;
        if (idx[v].count(u)) {
          int j = idx[v][u];
          adj[u][i].rev = j;
          adj[v][j].rev = i;
        }
      }
    }
  }
  edge twin(edge e) const { return adj[e.dst][e.rev]; }
  edge next(edge e) const {
    int j = adj[e.dst][e.rev].id + 1;
    if (j >= adj[e.dst].size()) j = 0;
    return adj[e.dst][j];
  }
  edge outer() const {
    int s = 0;
    for (int i = 1; i < n; ++i) if (ps[i] < ps[s]) s = i;
    for (int i = 0; i < adj[s].size(); ++i) {
      edge e1 = adj[s][i], e2 = adj[s][(i+1)%adj[s].size()];
      if (cross(ps[e1.dst]-ps[s], ps[e2.dst]-ps[s]) <= 0) return e1;
    }
  }
};
istream &operator>>(istream &is, point &p) { is>>p.x>>p.y;return is; }
ostream &operator<<(ostream &os, const point &p) { os<<"("<<p.x<<","<<p.y<<")"; return os; }


struct visualizer {
  double minx, maxx, miny, maxy, scale; 
  ofstream ofs;
  visualizer(string s = "data.js") : ofs(s) { 
    minx = miny =  1.0/0.0;
    maxx = maxy = -1.0/0.0;
  }
  void update(point p) {
    minx = min(minx, p.x); miny = min(miny, p.y);
    maxx = max(maxx, p.x); maxy = max(maxy, p.y);
    scale = 480/(max({maxx-minx, maxy-miny,1.0}));
  }
  double X(point p) { return scale * (p.x-minx) + 10; }
  double Y(point p) { return 490 - scale * (p.y-miny); }
  vector<point> ps;
  vector<segment> ss;
  visualizer &operator<<(point p) { ps.push_back(p); update(p); return *this; }
  visualizer &operator<<(segment s) { ss.push_back(s); update(s.p); update(s.q); return *this; }
  ~visualizer() {
    for (point p: ps) 
      ofs << "circle(" << X(p) << "," << Y(p) << ",3.0)" << endl;
    for (segment s: ss) 
      ofs << "line(" << X(s.p) << "," << Y(s.p) << "," 
                     << X(s.q) << "," << Y(s.q) << ")" << endl;
  }
};


int main() {
  for (int c, w; ~scanf("%d %d", &c, &w) && c; ) {
    vector<point> ps(c);
    for (int i = 0; i < c; ++i) {
      scanf("%lf %lf", &ps[i].x, &ps[i].y);
    }
    vector<segment> ss;
    for (int i = 0; i < w; ++i) {
      int u, v; scanf("%d %d", &u, &v);
      ss.push_back({ps[u-1], ps[v-1]});
    }
    arrangement arr(ss);
    /*
    visualizer vis;
    for (int i = 0; i < arr.n; ++i) {
      cerr << i << ": " << arr.ps[i] << endl;
      vis << arr.ps[i];
      for (auto e: arr.adj[i]) {
        vis << segment({arr.ps[e.src], arr.ps[e.dst]});
      }
    }
    */

    typedef arrangement::edge edge;
    edge e = arr.outer(); // outer-face edge

    vector<unordered_map<int,int>> step(arr.n);
    queue<edge> que;
    auto proceed = [&](edge s, int value) {
      if (step[s.src].count(s.dst)) return;
      //cerr << "proceed edge " << arr.ps[e.src] << arr.ps[e.dst] << endl;
      edge e = s;
      do {
        //cerr << "  mark " << arr.ps[e.src] << arr.ps[e.dst] << endl;
        step[e.src][e.dst] = value;
        que.push(arr.twin(e));
        e = arr.next(e);
      } while (e.src != s.src || e.dst != s.dst);
    };
    proceed(e, 0);
    int ans = 0;
    while (!que.empty()) {
      edge e = que.front(); que.pop();
      ans = step[e.dst][e.src];
      proceed(e, ans + 1);
    }
    printf("%d\n", ans);
  }
}