Problem:
Problem E:
Kuru-Kuru Robot
ロボット工学の研究者であるアシモフ博士は、新しいロボットの開発に成功した。このロボットは、床に張り巡らせた特殊なワイヤーに沿って自由に動くことができる。ロボットは常に現在いるワイヤーに平行な方向を向いて前進する。
すばらしいことに、このロボットはワイヤー上を移動するためにその距離にかかわらずエネルギーを消費しない。しかし、ワイヤーの端点やワイヤーの交点で向きを変えるためにはその点を中心に回転する必要があり、その回転角度だけエネルギーを消費する。
このロボットをスタート地点からゴール地点まで動かしたい。例えば、下図においてロボットを start に東向き（下図
x
軸の正の向き）で配置し goal まで動かしてみよう。start から交点 A 交点 B を経由して goal にたどり着く経路と、交点 A 交点 C を経由する経路があるが、前者の方が移動距離が長いものの回転角度が少ないためエネルギー消費量は少ない。
あなたの仕事は、床にあるワイヤーの位置、スタート地点、ゴール地点を読み込み、スタート地点からゴール地点へ移動するために必要な回転角度の合計の最小値を報告するプログラムを作成することである。
ロボットはスタート地点においてどのような向きに配置してもよく、ゴール地点ではどの方向を向いていてもよい。
Input
入力は複数のデータセットからなる。各データセットの形式は以下のとおり：
n
x
1
1
y
1
1
x
2
1
y
2
1
x
1
2
y
1
2
x
2
2
y
2
2
.
   .
   .
x
1
n
y
1
n
x
2
n
y
2
n
sx
sy
gx
gy
n
はワイヤーの数を示す整数である。
x
1
i
y
1
i
は
i
番目のワイヤーの一方の端点の座標、
x
2
i
y
2
i
は
i
番目のワイヤーのもう一方の端点の座標を示す。
sx
sy
、
gx
gy
はそれぞれスタート地点とゴール地点の座標を示す。
与えられる座標はすべて整数値であり、
x
軸
y
軸の値は -1000　以上 1000 以下である。また、スタート地点とゴール地点は与えられるワイヤーの端点上にあると仮定してよい。
n
≤ 50 であると仮定してよい。
n
が 0 のとき入力の終了を示す。
Output
各データセットに対して、回転角度の合計の最小値を１行に出力せよ。ロボットがゴール地点にたどり着けない場合は "-1" と出力せよ。出力は 0.00001 以下の誤差を含んでもよい。
Sample Input
8
1 3 11 3
5 3 13 11
10 10 17 10
11 2 11 6
10 5 14 5
13 6 13 2
17 10 17 3
13 3 19 3
1 3 19 3
6
1 3 11 3
5 3 13 11
10 10 17 10
11 2 11 6
10 5 14 5
13 3 19 3
1 3 19 3
2
0 0 7 0
3 0 7 3
0 0 7 3
0
Output for the Sample Input
270.0000
-1
36.86989765

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
#define f first
#define s second
#define mp make_pair
#define pi M_PI
#define inf 1e14
#define eps (1e-8)
#define MAX 1000
#define equals(a,b) (fabs((a)-(b))<eps)
using namespace std;
 
class Point{
public:
  double x,y;
  Point(double x=0,double y=0):x(x),y(y){}
 
  Point operator+(Point p){ return Point(x+p.x,y+p.y);}
  Point operator-(Point p){ return Point(x-p.x,y-p.y);}
  Point operator*(double k){ return Point(x*k,y*k);}
  Point operator/(double k){ return Point(x/k,y/k);}
  bool operator<(Point p)const{ return (x!=p.x ? x<p.x : y<p.y);}
  bool operator==(Point p)const{ return fabs(x-p.x)<eps && fabs(y-p.y)<eps;}
 
  double abs(){ return sqrt(norm());}
  double norm(){ return (x*x+y*y);}
};
typedef Point Vector;
typedef vector<Point> Polygon;
 
class Segment{
public:
  Point p1,p2;
  Segment(Point p1=Point(),Point p2=Point()):p1(p1),p2(p2){}
};
typedef Segment Line;
 
double norm(Vector a){ return (a.x*a.x+a.y*a.y);}
double abs(Vector a){ return sqrt(norm(a));}
double dot(Vector a,Vector b){ return (a.x*b.x+a.y*b.y);}
double cross(Vector a,Vector b){ return (a.x*b.y-a.y*b.x);}
 
bool isParallel(Segment s,Segment t){
  return equals(cross(s.p1-s.p2,t.p1-t.p2),0.0);
}
 
int ccw(Point p0,Point p1,Point p2){
  Vector a=p1-p0;
  Vector b=p2-p0;
  if(cross(a,b)>eps)return 1;
  if(cross(a,b)<-eps)return -1;
  if(dot(a,b)<-eps)return 2;
  if(a.norm()<b.norm())return -2;
  return 0;
}
 
bool intersect(Point p1,Point p2,Point p3,Point p4){
  return (ccw(p1,p2,p3)*ccw(p1,p2,p4)<=0 &&
          ccw(p3,p4,p1)*ccw(p3,p4,p2)<=0);
}
 
bool intersect(Segment s1,Segment s2){
  return intersect(s1.p1,s1.p2,s2.p1,s2.p2);
}
 
Point getCrossPointLL(Line a,Line b){
  double A=cross(a.p2-a.p1,b.p2-b.p1);
  double B=cross(a.p2-a.p1,a.p2-b.p1);
  if(abs(A)<eps || abs(B)<eps)return b.p1;
  return b.p1+(b.p2-b.p1)*(B/A);
}
 
bool merge_if_able(Segment &s,Segment t) {
  if(!isParallel(s,t))return false;
  if(ccw(s.p1,t.p1,s.p2)==1 ||
     ccw(s.p1,t.p1,s.p2)==-1)return false;
  if(ccw(s.p1,s.p2,t.p1)==-2 ||
     ccw(t.p1,t.p2,s.p1)==-2)return false;
  s=Segment(min(s.p1,t.p1),max(s.p2,t.p2));
  return true;
}
 
void merge(vector<Segment>& v) {
  for(int i=0;i<v.size();i++){
    if(v[i].p2<v[i].p1)swap(v[i].p2,v[i].p1);
  }
  for(int i=0;i<v.size();i++)
    for(int j=i+1;j<v.size();j++)
      if(merge_if_able(v[i],v[j]))
        v[j--]=v.back(),v.pop_back();
}
 
typedef vector<vector<int> > Graph;
Graph SegmentArrangement(vector<Segment> v,vector<Point> &ps){
  for(int i=0;i<v.size();i++){
    ps.push_back(v[i].p1);
    ps.push_back(v[i].p2);
    for(int j=i+1;j<v.size();j++){
      if(intersect(v[i],v[j]))ps.push_back(getCrossPointLL(v[i],v[j]));
    }
  }
  sort(ps.begin(),ps.end());
  ps.erase(unique(ps.begin(),ps.end()),ps.end());
  Graph g(ps.size());
  for(int i=0;i<v.size();i++){
    vector<pair<double,int> > list;
    for(int j=0;j<ps.size();j++)
      if(ccw(v[i].p1,v[i].p2,ps[j])==0)
        list.push_back(mp(norm(v[i].p1-ps[j]),j));
    sort(list.begin(),list.end());
    for(int j=0;j<list.size()-1;j++){
      int a=list[j].s,b=list[j+1].s;
      g[a].push_back(b);
      g[b].push_back(a);
    }
  }
  return g;
}
class State{
  public:
    int n,b;
    double cost;
    State(int n,int b,double cost):n(n),b(b),cost(cost){}
    bool operator<(State s)const{
      return s.cost-cost<-eps;
    }
};
Graph e;
vector<Point> vp;
Point a,b;
double getAngle(Vector v1,Vector v2){
  double r=dot(v1,v2)/(abs(v1)*abs(v2));
  if(r<-1.0)r=-1.0;
  if(1.0<r)r=1.0;
  return (acos(r)*180.0/pi);
}
double dijkstra(){
  int s=0,g=0;
  double d[MAX][MAX];
  priority_queue<State> pq;
  for(int i=0;i<vp.size();i++){
    if(vp[i]==a)s=i;
    if(vp[i]==b)g=i;
  }
  for(int i=0;i<MAX;i++)for(int j=0;j<MAX;j++)d[i][j]=inf;
  for(int i=0;i<e[s].size();i++){
    d[e[s][i]][s]=0;
    pq.push(State(e[s][i],s,0));
  }
  while(pq.size()){
    State u=pq.top();
    pq.pop();
    if(u.n==g)return u.cost;
    if(d[u.n][u.b]-u.cost<-eps)continue;
    for(int i=0;i<e[u.n].size();i++){
      int next=e[u.n][i];
      if(next==u.b)continue;
      double cost=getAngle(vp[u.n]-vp[u.b],vp[next]-vp[u.n]);
      if(u.cost+cost-d[next][u.n]<-eps){
        d[next][u.n]=u.cost+cost;
        pq.push(State(next,u.n,d[next][u.n]));
      }
    }
  }
  return -1;
}
int main()
{
  int n;
 
  while(1){
    cin>>n;
    if(n==0)break;
    vector<Segment> vs;
    for(int i=0;i<n;i++){
      int x1,y1,x2,y2;
      cin>>x1>>y1>>x2>>y2;
      vs.push_back(Segment(Point(x1,y1),Point(x2,y2)));
    }
    cin>>a.x>>a.y>>b.x>>b.y;
    vp.clear();
    vp.push_back(a);
    vp.push_back(b);
    merge(vs);
    e=SegmentArrangement(vs,vp);
    double ans=dijkstra();
    if(ans==-1)cout<<-1<<endl;
    else printf("%.10f\n",dijkstra());
  }
}
accuracy: 1
time_ms: 30
memory_kb: 11172
final_rank: 13

code_snippet: #include<bits/stdc++.h>
#define f first
#define s second
#define mp make_pair
#define pi M_PI
#define inf 1e14
#define eps (1e-8)
#define MAX 1000
#define equals(a,b) (fabs((a)-(b))<eps)
using namespace std;

class Point{
public:
  double x,y;
  Point(double x=0,double y=0):x(x),y(y){}

  Point operator+(Point p){ return Point(x+p.x,y+p.y);}
  Point operator-(Point p){ return Point(x-p.x,y-p.y);}
  Point operator*(double k){ return Point(x*k,y*k);}
  Point operator/(double k){ return Point(x/k,y/k);}
  bool operator<(Point p)const{ return (x!=p.x ? x<p.x : y<p.y);}
  bool operator==(Point p)const{ return fabs(x-p.x)<eps && fabs(y-p.y)<eps;}

  double abs(){ return sqrt(norm());}
  double norm(){ return (x*x+y*y);}
};
typedef Point Vector;
typedef vector<Point> Polygon;

class Segment{
public:
  Point p1,p2;
  Segment(Point p1=Point(),Point p2=Point()):p1(p1),p2(p2){}
};
typedef Segment Line;

double norm(Vector a){ return (a.x*a.x+a.y*a.y);}
double abs(Vector a){ return sqrt(norm(a));}
double dot(Vector a,Vector b){ return (a.x*b.x+a.y*b.y);}
double cross(Vector a,Vector b){ return (a.x*b.y-a.y*b.x);}

bool isParallel(Segment s,Segment t){
  return equals(cross(s.p1-s.p2,t.p1-t.p2),0.0);
}

int ccw(Point p0,Point p1,Point p2){
  Vector a=p1-p0;
  Vector b=p2-p0;
  if(cross(a,b)>eps)return 1;
  if(cross(a,b)<-eps)return -1;
  if(dot(a,b)<-eps)return 2;
  if(a.norm()<b.norm())return -2;
  return 0;
}

bool intersect(Point p1,Point p2,Point p3,Point p4){
  return (ccw(p1,p2,p3)*ccw(p1,p2,p4)<=0 &&
          ccw(p3,p4,p1)*ccw(p3,p4,p2)<=0);
}

bool intersect(Segment s1,Segment s2){
  return intersect(s1.p1,s1.p2,s2.p1,s2.p2);
}

Point getCrossPointLL(Line a,Line b){
  double A=cross(a.p2-a.p1,b.p2-b.p1);
  double B=cross(a.p2-a.p1,a.p2-b.p1);
  if(abs(A)<eps || abs(B)<eps)return b.p1;
  return b.p1+(b.p2-b.p1)*(B/A);
}

bool merge_if_able(Segment &s,Segment t) {
  if(!isParallel(s,t))return false;
  if(ccw(s.p1,t.p1,s.p2)==1 ||
     ccw(s.p1,t.p1,s.p2)==-1)return false;
  if(ccw(s.p1,s.p2,t.p1)==-2 ||
     ccw(t.p1,t.p2,s.p1)==-2)return false;
  s=Segment(min(s.p1,t.p1),max(s.p2,t.p2));
  return true;
}

void merge(vector<Segment>& v) {
  for(int i=0;i<v.size();i++){
    if(v[i].p2<v[i].p1)swap(v[i].p2,v[i].p1);
  }
  for(int i=0;i<v.size();i++)
    for(int j=i+1;j<v.size();j++)
      if(merge_if_able(v[i],v[j]))
        v[j--]=v.back(),v.pop_back();
}

typedef vector<vector<int> > Graph;

Graph SegmentArrangement(vector<Segment> v,vector<Point> &ps){
  for(int i=0;i<v.size();i++){
    ps.push_back(v[i].p1);
    ps.push_back(v[i].p2);
    for(int j=i+1;j<v.size();j++){
      if(intersect(v[i],v[j]))ps.push_back(getCrossPointLL(v[i],v[j]));
    }
  }
  sort(ps.begin(),ps.end());
  ps.erase(unique(ps.begin(),ps.end()),ps.end());
  Graph g(ps.size());
  for(int i=0;i<v.size();i++){
    vector<pair<double,int> > list;
    for(int j=0;j<ps.size();j++)
      if(ccw(v[i].p1,v[i].p2,ps[j])==0)
        list.push_back(mp(norm(v[i].p1-ps[j]),j));
    sort(list.begin(),list.end());
    for(int j=0;j<list.size()-1;j++){
      int a=list[j].s,b=list[j+1].s;
      g[a].push_back(b);
      g[b].push_back(a);
    }
  }
  return g;
}

class State{
  public:
    int n,b;
    double cost;
    State(int n,int b,double cost):n(n),b(b),cost(cost){}
    bool operator<(State s)const{
      return s.cost-cost<-eps;
    }
};

Graph e;
vector<Point> vp;
Point a,b;

double getAngle(Vector v1,Vector v2){
  double r=dot(v1,v2)/(abs(v1)*abs(v2));
  if(r<-1.0)r=-1.0;
  if(1.0<r)r=1.0;
  return (acos(r)*180.0/pi);
}

double dijkstra(){
  int s=0,g=0;
  double d[MAX][MAX];
  priority_queue<State> pq;
  for(int i=0;i<vp.size();i++){
    if(vp[i]==a)s=i;
    if(vp[i]==b)g=i;
  }
  for(int i=0;i<MAX;i++)for(int j=0;j<MAX;j++)d[i][j]=inf;
  for(int i=0;i<e[s].size();i++){
    d[e[s][i]][s]=0;
    pq.push(State(e[s][i],s,0));
  }

  while(pq.size()){
    State u=pq.top();
    pq.pop();

    if(u.n==g)return u.cost;
    if(d[u.n][u.b]-u.cost<-eps)continue;

    for(int i=0;i<e[u.n].size();i++){
      int next=e[u.n][i];
      if(next==u.b)continue;
      double cost=getAngle(vp[u.n]-vp[u.b],vp[next]-vp[u.n]);
      if(u.cost+cost-d[next][u.n]<-eps){
        d[next][u.n]=u.cost+cost;
        pq.push(State(next,u.n,d[next][u.n]));
      }
    }
  }
  return -1;
}

int main()
{
  int n;

  while(1){
    cin>>n;
    if(n==0)break;
    vector<Segment> vs;
    for(int i=0;i<n;i++){
      int x1,y1,x2,y2;
      cin>>x1>>y1>>x2>>y2;
      vs.push_back(Segment(Point(x1,y1),Point(x2,y2)));
    }
    cin>>a.x>>a.y>>b.x>>b.y;
    vp.clear();
    vp.push_back(a);
    vp.push_back(b);
    merge(vs);
    e=SegmentArrangement(vs,vp);
    double ans=dijkstra();
    if(ans==-1)cout<<-1<<endl;
    else printf("%.10f\n",dijkstra());
  }
  return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 11156
final_rank: 12

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)
using namespace std;
typedef long long LL;

typedef complex<double> P;
const double EPS = 1e-8;

// 誤差を加味した符号判定
int sign(double x){ return x > EPS ? 1 : x < -EPS ? -1 : 0; }

// 内積・外積
double dot(P a, P b){return real(conj(a) * b);}
double cross(P a, P b){return imag(conj(a) * b);}

// OAとOBのなす符号付き角度 [-pi, pi]
// example : (1, 0), (0, 1) -> pi/2
double angle(P a, P b){return arg(conj(a) * b);}

// aをc中心にb[rad]回転
P rotate(P a, double b, P c = P()){return (a - c) * polar(1.0, b) + c;}

int ccw(P a, P b, P c) {
    b -= a; c -= a;
    if (cross(b, c) > +EPS)   return +1; // 反時計回り
    if (cross(b, c) < -EPS)   return -1; // 時計回り
    if (dot(b, c) < -EPS)     return +2; // c--a--b の順番で一直線上
    if (norm(b) + EPS < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}

enum{ OUT, ON, IN };

// Pointの比較をしたいときだけ定義する．
namespace std{
    bool operator < (const P& a, const P& b) {
        return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
    }
};

typedef vector<P> L;
P vec(L l){return l[1] - l[0];}

// 線分と点の交差判定(端点の処理に注意)(端点は含むけれども誤差に注意)
// verify : AOJ1279, AOJ2506
bool iSP(L s, P p) {return ccw(s[0], s[1], p) == 0;}

// 直線と直線の交点
// Verified: AOJ2579
// size()によって場合分け
// *4 : 直線が重なる  *1 : 交点が1つ存在 *0 : 直線が交差しない
vector<P> pLL(L l, L m){
    double A = cross(vec(l), vec(m));
    double B = cross(vec(l), l[1] - m[0]);
    if(sign(A) == 0 && sign(B) == 0) return {l[0], l[1], m[0], m[1]}; // 二直線が重なっている
    if(sign(A) == 0) return{}; // 直線が交わらない
    return {m[0] + vec(m) * B / A};
}

vector<P> pSS(L l, L m){
    vector<P> res;
    auto find = [&](P p){ 
        for(P r : res) if(sign(abs(r - p)) == 0)
                return true;
        return false;
    };
    for(P p : pLL(l, m))
        if(iSP(l,p) && iSP(m,p) && !find(p)) // 片方が直線の場合は適宜変えること
            res.push_back(p);
    return res;
}

// 入力
// ss : 線分のリスト
//
// 出力
// ps : グラフの頂点番号に対応する点が入る
// 返り値 : 上の説明のグラフ
//
// Verified
// AOJ 2113
typedef vector<int> Node;
typedef vector<Node> Graph;
Graph segment_arrangement(const vector<L> &ss, vector<P> &ps) {
    for (int i = 0; i < ss.size(); i++) {
        ps.push_back( ss[i][0] );
        ps.push_back( ss[i][1] );
        for (int j = i+1; j < ss.size(); j++){
            auto cp = pSS(ss[i], ss[j]);
            if (!cp.empty()) {
                assert(cp.size() == 1);
                ps.push_back( cp.back() );
            }
        }
    }
    sort(ps.begin(), ps.end());
    ps.erase(unique(ps.begin(), ps.end()), ps.end());

    Graph g(ps.size());
    for (int i = 0; i < ss.size(); i++) {
        vector<int> on;
        for (int j = 0; j < ps.size(); j++){
            if (iSP(ss[i], ps[j])){
                on.push_back(j);
            }
        }
        for (int j = 0; j + 1 < on.size(); j++) {
            for(int k = j + 1; k < on.size(); k++) {
                int a = on[j], b = on[k];
                g[a].push_back( b );
                g[b].push_back( a );
            }
        }
    }
    return g;
}

// 線分併合
//
// 線分のリストからオーバーラップするものたちをまとめ,新しい線分のリストを作る.
// 元々の線分のリストにおける順番は破壊される．
//
// not verified
void merge_segments(vector<L>& segs) {
    auto merge_if_able = [](L& s, L t){
        if (abs(cross(s[1]-s[0], t[1]-t[0])) > EPS) return false;
        //if (sign(cross(vec(s), vec(t))) != 0) return false;
        if (ccw(s[0], t[0], s[1]) == +1 ||
                ccw(s[0], t[0], s[1]) == -1) return false; // not on the same line
        if (ccw(s[0], s[1], t[0]) == -2 ||
                ccw(t[0], t[1], s[0]) == -2) return false; // separated
        s = { min(s[0], t[0]), max(s[1], t[1]) };
        return true;
    };
    for (int i = 0; i < segs.size(); ++i)
        if (segs[i][1] < segs[i][0])
            swap(segs[i][1], segs[i][0]);
    for (int i = 0; i < segs.size(); ++i)
        for (int j = i+1; j < segs.size(); ++j)
            if (merge_if_able(segs[i], segs[j]))
                segs[j--] = segs.back(), segs.pop_back();
}
P input() {
    double x, y;
    cin >> x >> y;
    return {x, y};
}
typedef tuple<double, int, int> T;
const int MAX = 500;
const double INF = 1e64;

int main(){
    int n;
    while(cin >> n && n > 0){
        vector<L> lines(n);
        REP(i, n) {
            P a = input();
            P b = input();
            lines[i] = {a, b};
        }

        //merge_segments(lines);
        //assert(size == lines.size());

        vector<P> ps;
        Graph G = segment_arrangement(lines, ps);
        /*
        REP(i, G.size()){
            cout << i << ":";
            for(int v : G[i]) cout << v << " ";
            cout << endl;
        }
        */
        assert(ps.size() < MAX);

        REP(i, ps.size()) REP(j, i) {
            assert(abs(ps[i] - ps[j]) > EPS);
        }

        auto find = [](const vector<P>& pv, P p) -> int {
            for(int i = 0; i < pv.size(); i++) {
                auto q = pv[i];
                if(abs(p - q) < EPS) {
                    return i;
                }
            }
            return -1;
        };
        
        P sp = input();
        P gp = input();
        int s = find(ps, sp);
        int g = find(ps, gp);

        /*
        if(s == g) {
            cout << 0 << endl;
            continue;
        }
        */

        assert(s != -1 && g != -1);

        priority_queue<T, vector<T>, greater<T>> que;
        double dist[MAX][MAX] = {};
        REP(i, MAX) REP(j, MAX) dist[i][j] = INF;
        for(int u : G[s]) {
            dist[s][u] = 0.0;
            que.push(T(0.0, s, u));
        }
        double ans = INF;
        while(!que.empty()) {
            T t = que.top(); que.pop();
            double d;
            int u, v;
            tie(d, u, v) = t;
            if(v == g) {
                ans = d;
                break;
            }
            for(int w : G[v]) {
                P p = ps[v] - ps[u];
                P q = ps[w] - ps[v];
                double th = abs(angle(p, q)) / M_PI * 180.0;
                double nd = d + th;
                if(dist[v][w] > nd) {
                    dist[v][w] = nd;
                    que.push(T(nd, v, w));
                }
            }
        }
        if(ans == INF) {
            cout << -1 << endl;
        } else {
            printf("%.12f\n", ans);
        }
    }

    return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3368
final_rank: 7

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)
using namespace std;
typedef long long LL;

typedef complex<double> P;
const double EPS = 1e-8;

// 誤差を加味した符号判定
int sign(double x){ return x > EPS ? 1 : x < -EPS ? -1 : 0; }

// 内積・外積
double dot(P a, P b){return real(conj(a) * b);}
double cross(P a, P b){return imag(conj(a) * b);}

// OAとOBのなす符号付き角度 [-pi, pi]
// example : (1, 0), (0, 1) -> pi/2
double angle(P a, P b){return arg(conj(a) * b);}

// aをc中心にb[rad]回転
P rotate(P a, double b, P c = P()){return (a - c) * polar(1.0, b) + c;}

int ccw(P a, P b, P c) {
    b -= a; c -= a;
    if (cross(b, c) > +EPS)   return +1; // 反時計回り
    if (cross(b, c) < -EPS)   return -1; // 時計回り
    if (dot(b, c) < -EPS)     return +2; // c--a--b の順番で一直線上
    if (norm(b) + EPS < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}

enum{ OUT, ON, IN };

// Pointの比較をしたいときだけ定義する．
namespace std{
    bool operator < (const P& a, const P& b) {
        return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
    }
};

typedef vector<P> L;
P vec(L l){return l[1] - l[0];}

// 線分と点の交差判定(端点の処理に注意)(端点は含むけれども誤差に注意)
// verify : AOJ1279, AOJ2506
bool iSP(L s, P p) {return ccw(s[0], s[1], p) == 0;}

// 直線と直線の交点
// Verified: AOJ2579
// size()によって場合分け
// *4 : 直線が重なる  *1 : 交点が1つ存在 *0 : 直線が交差しない
vector<P> pLL(L l, L m){
    double A = cross(vec(l), vec(m));
    double B = cross(vec(l), l[1] - m[0]);
    if(sign(A) == 0 && sign(B) == 0) return {l[0], l[1], m[0], m[1]}; // 二直線が重なっている
    if(sign(A) == 0) return{}; // 直線が交わらない
    return {m[0] + vec(m) * B / A};
}

vector<P> pSS(L l, L m){
    vector<P> res;
    auto find = [&](P p){ 
        for(P r : res) if(sign(abs(r - p)) == 0)
                return true;
        return false;
    };
    for(P p : pLL(l, m))
        if(iSP(l,p) && iSP(m,p) && !find(p)) // 片方が直線の場合は適宜変えること
            res.push_back(p);
    return res;
}

// 入力
// ss : 線分のリスト
//
// 出力
// ps : グラフの頂点番号に対応する点が入る
// 返り値 : 上の説明のグラフ
//
// Verified
// AOJ 2113
typedef vector<int> Node;
typedef vector<Node> Graph;
Graph segment_arrangement(const vector<L> &ss, vector<P> &ps) {
    for (int i = 0; i < ss.size(); i++) {
        ps.push_back( ss[i][0] );
        ps.push_back( ss[i][1] );
        for (int j = i+1; j < ss.size(); j++){
            auto cp = pSS(ss[i], ss[j]);
            if (!cp.empty()) {
                assert(cp.size() == 1);
                ps.push_back( cp.back() );
            }
        }
    }
    sort(ps.begin(), ps.end());
    ps.erase(unique(ps.begin(), ps.end()), ps.end());

    Graph g(ps.size());
    for (int i = 0; i < ss.size(); i++) {
        vector<int> on;
        for (int j = 0; j < ps.size(); j++){
            if (iSP(ss[i], ps[j])){
                on.push_back(j);
            }
        }
        for (int j = 0; j + 1 < on.size(); j++) {
            for(int k = j + 1; k < on.size(); k++) {
                int a = on[j], b = on[k];
                g[a].push_back( b );
                g[b].push_back( a );
            }
        }
    }
    return g;
}

// 線分併合
//
// 線分のリストからオーバーラップするものたちをまとめ,新しい線分のリストを作る.
// 元々の線分のリストにおける順番は破壊される．
//
// not verified
void merge_segments(vector<L>& segs) {
    auto merge_if_able = [](L& s, L t){
        if (abs(cross(s[1]-s[0], t[1]-t[0])) > EPS) return false;
        //if (sign(cross(vec(s), vec(t))) != 0) return false;
        if (ccw(s[0], t[0], s[1]) == +1 ||
                ccw(s[0], t[0], s[1]) == -1) return false; // not on the same line
        if (ccw(s[0], s[1], t[0]) == -2 ||
                ccw(t[0], t[1], s[0]) == -2) return false; // separated
        s = { min(s[0], t[0]), max(s[1], t[1]) };
        return true;
    };
    for (int i = 0; i < segs.size(); ++i)
        if (segs[i][1] < segs[i][0])
            swap(segs[i][1], segs[i][0]);
    for (int i = 0; i < segs.size(); ++i)
        for (int j = i+1; j < segs.size(); ++j)
            if (merge_if_able(segs[i], segs[j]))
                segs[j--] = segs.back(), segs.pop_back();
}
P input() {
    double x, y;
    cin >> x >> y;
    return {x, y};
}
typedef tuple<double, int, int> T;
const int MAX = 500;
const double INF = 1e64;

int main(){
    int n;
    while(cin >> n && n > 0){
        vector<L> lines(n);
        REP(i, n) {
            P a = input();
            P b = input();
            lines[i] = {a, b};
        }

        merge_segments(lines);
        //assert(size == lines.size());

        vector<P> ps;
        Graph G = segment_arrangement(lines, ps);
        /*
        REP(i, G.size()){
            cout << i << ":";
            for(int v : G[i]) cout << v << " ";
            cout << endl;
        }
        */
        assert(ps.size() < MAX);

        REP(i, ps.size()) REP(j, i) {
            assert(abs(ps[i] - ps[j]) > EPS);
        }

        auto find = [](const vector<P>& pv, P p) -> int {
            for(int i = 0; i < pv.size(); i++) {
                auto q = pv[i];
                if(abs(p - q) < EPS) {
                    return i;
                }
            }
            return -1;
        };
        
        P sp = input();
        P gp = input();
        int s = find(ps, sp);
        int g = find(ps, gp);

        /*
        if(s == g) {
            cout << 0 << endl;
            continue;
        }
        */

        assert(s != -1 && g != -1);

        priority_queue<T, vector<T>, greater<T>> que;
        double dist[MAX][MAX] = {};
        REP(i, MAX) REP(j, MAX) dist[i][j] = INF;
        for(int u : G[s]) {
            dist[s][u] = 0.0;
            que.push(T(0.0, s, u));
        }
        double ans = INF;
        while(!que.empty()) {
            T t = que.top(); que.pop();
            double d;
            int u, v;
            tie(d, u, v) = t;
            if(v == g) {
                ans = d;
                break;
            }
            for(int w : G[v]) {
                P p = ps[v] - ps[u];
                P q = ps[w] - ps[v];
                double th = abs(angle(p, q)) / M_PI * 180.0;
                double nd = d + th;
                if(dist[v][w] > nd) {
                    dist[v][w] = nd;
                    que.push(T(nd, v, w));
                }
            }
        }
        if(ans == INF) {
            cout << -1 << endl;
        } else {
            printf("%.12f\n", ans);
        }
    }

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3368
final_rank: 4

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)
using namespace std;
typedef long long LL;

typedef complex<double> P;
const double EPS = 1e-8;

// 誤差を加味した符号判定
int sign(double x){ return x > EPS ? 1 : x < -EPS ? -1 : 0; }

// 内積・外積
double dot(P a, P b){return real(conj(a) * b);}
double cross(P a, P b){return imag(conj(a) * b);}

// OAとOBのなす符号付き角度 [-pi, pi]
// example : (1, 0), (0, 1) -> pi/2
double angle(P a, P b){return arg(conj(a) * b);}

// aをc中心にb[rad]回転
P rotate(P a, double b, P c = P()){return (a - c) * polar(1.0, b) + c;}

int ccw(P a, P b, P c) {
    b -= a; c -= a;
    if (cross(b, c) > +EPS)   return +1; // 反時計回り
    if (cross(b, c) < -EPS)   return -1; // 時計回り
    if (dot(b, c) < -EPS)     return +2; // c--a--b の順番で一直線上
    if (norm(b) + EPS < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}

enum{ OUT, ON, IN };

// Pointの比較をしたいときだけ定義する．
namespace std{
    bool operator < (const P& a, const P& b) {
        return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
    }
};

typedef vector<P> L;
P vec(L l){return l[1] - l[0];}

// 線分と点の交差判定(端点の処理に注意)(端点は含むけれども誤差に注意)
// verify : AOJ1279, AOJ2506
bool iSP(L s, P p) {return ccw(s[0], s[1], p) == 0;}

// 直線と直線の交点
// Verified: AOJ2579
// size()によって場合分け
// *4 : 直線が重なる  *1 : 交点が1つ存在 *0 : 直線が交差しない
vector<P> pLL(L l, L m){
    double A = cross(vec(l), vec(m));
    double B = cross(vec(l), l[1] - m[0]);
    if(sign(A) == 0 && sign(B) == 0) return {l[0], l[1], m[0], m[1]}; // 二直線が重なっている
    if(sign(A) == 0) return{}; // 直線が交わらない
    return {m[0] + vec(m) * B / A};
}

vector<P> pSS(L l, L m){
    vector<P> res;
    auto find = [&](P p){ 
        for(P r : res) if(sign(abs(r - p)) == 0)
                return true;
        return false;
    };
    for(P p : pLL(l, m))
        if(iSP(l,p) && iSP(m,p) && !find(p)) // 片方が直線の場合は適宜変えること
            res.push_back(p);
    return res;
}

// 入力
// ss : 線分のリスト
//
// 出力
// ps : グラフの頂点番号に対応する点が入る
// 返り値 : 上の説明のグラフ
//
// Verified
// AOJ 2113
typedef vector<int> Node;
typedef vector<Node> Graph;
Graph segment_arrangement(const vector<L> &ss, vector<P> &ps) {
    for (int i = 0; i < ss.size(); i++) {
        ps.push_back( ss[i][0] );
        ps.push_back( ss[i][1] );
        for (int j = i+1; j < ss.size(); j++){
            auto cp = pSS(ss[i], ss[j]);
            if (!cp.empty()) {
                assert(cp.size() == 1);
                ps.push_back( cp.back() );
            }
        }
    }
    sort(ps.begin(), ps.end());
    ps.erase(unique(ps.begin(), ps.end()), ps.end());

    Graph g(ps.size());
    for (int i = 0; i < ss.size(); i++) {
        vector<int> on;
        for (int j = 0; j < ps.size(); j++){
            if (iSP(ss[i], ps[j])){
                on.push_back(j);
            }
        }
        for (int j = 0; j + 1 < on.size(); j++) {
            for(int k = j + 1; k < on.size(); k++) {
                int a = on[j], b = on[k];
                g[a].push_back( b );
                g[b].push_back( a );
            }
        }
    }
    return g;
}

// 線分併合
//
// 線分のリストからオーバーラップするものたちをまとめ,新しい線分のリストを作る.
// 元々の線分のリストにおける順番は破壊される．
//
// not verified
void merge_segments(vector<L>& segs) {
    auto merge_if_able = [](L& s, L t){
        if (abs(cross(s[1]-s[0], t[1]-t[0])) > EPS) return false;
        //if (sign(cross(vec(s), vec(t))) != 0) return false;
        if (ccw(s[0], t[0], s[1]) == +1 ||
                ccw(s[0], t[0], s[1]) == -1) return false; // not on the same line
        if (ccw(s[0], s[1], t[0]) == -2 ||
                ccw(t[0], t[1], s[0]) == -2) return false; // separated
        s = { min(s[0], t[0]), max(s[1], t[1]) };
        return true;
    };
    for (int i = 0; i < segs.size(); ++i)
        if (segs[i][1] < segs[i][0])
            swap(segs[i][1], segs[i][0]);
    for (int i = 0; i < segs.size(); ++i)
        for (int j = i+1; j < segs.size(); ++j)
            if (merge_if_able(segs[i], segs[j]))
                segs[j--] = segs.back(), segs.pop_back();
}
P input() {
    double x, y;
    cin >> x >> y;
    return {x, y};
}
typedef tuple<double, int, int> T;
const int MAX = 500;
const double INF = 1e64;

int main(){
    int n;
    while(cin >> n && n > 0){
        vector<L> lines(n);
        REP(i, n) {
            P a = input();
            P b = input();
            lines[i] = {a, b};
        }

        merge_segments(lines);
        //assert(size == lines.size());

        vector<P> ps;
        Graph G = segment_arrangement(lines, ps);
        /*
        REP(i, G.size()){
            cout << i << ":";
            for(int v : G[i]) cout << v << " ";
            cout << endl;
        }
        */
        assert(ps.size() < MAX);

        REP(i, ps.size()) REP(j, i) {
            assert(abs(ps[i] - ps[j]) > EPS);
        }

        auto find = [](const vector<P>& pv, P p) -> int {
            for(int i = 0; i < pv.size(); i++) {
                auto q = pv[i];
                if(abs(p - q) < EPS) {
                    return i;
                }
            }
            return -1;
        };
        
        P sp = input();
        P gp = input();
        int s = find(ps, sp);
        int g = find(ps, gp);

        /*
        if(s == g) {
            cout << 0 << endl;
            continue;
        }
        */

        assert(s != -1 && g != -1);

        priority_queue<T, vector<T>, greater<T>> que;
        double dist[MAX][MAX] = {};
        REP(i, MAX) REP(j, MAX) dist[i][j] = INF;
        for(int u : G[s]) {
            dist[s][u] = 0.0;
            que.push(T(0.0, s, u));
        }
        double ans = INF;
        while(!que.empty()) {
            T t = que.top(); que.pop();
            double d;
            int u, v;
            tie(d, u, v) = t;
            if(v == g) {
                ans = d;
                break;
            }
            for(int w : G[v]) if(u != w) {
                P p = ps[v] - ps[u];
                P q = ps[w] - ps[v];
                double th = abs(angle(p, q)) / M_PI * 180.0;
                double nd = d + th;
                if(dist[v][w] > nd) {
                    dist[v][w] = nd;
                    que.push(T(nd, v, w));
                }
            }
        }
        if(ans == INF) {
            cout << -1 << endl;
        } else {
            printf("%.12f\n", ans);
        }
    }

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3368
final_rank: 4

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)
using namespace std;
typedef long long LL;

typedef complex<double> P;
const double EPS = 1e-8;

// 誤差を加味した符号判定
int sign(double x){ return x > EPS ? 1 : x < -EPS ? -1 : 0; }

// 内積・外積
double dot(P a, P b){return real(conj(a) * b);}
double cross(P a, P b){return imag(conj(a) * b);}

// OAとOBのなす符号付き角度 [-pi, pi]
// example : (1, 0), (0, 1) -> pi/2
double angle(P a, P b){return arg(conj(a) * b);}

// aをc中心にb[rad]回転
P rotate(P a, double b, P c = P()){return (a - c) * polar(1.0, b) + c;}

int ccw(P a, P b, P c) {
    b -= a; c -= a;
    if (cross(b, c) > +EPS)   return +1; // 反時計回り
    if (cross(b, c) < -EPS)   return -1; // 時計回り
    if (dot(b, c) < -EPS)     return +2; // c--a--b の順番で一直線上
    if (norm(b) + EPS < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}

enum{ OUT, ON, IN };

// Pointの比較をしたいときだけ定義する．
namespace std{
    bool operator < (const P& a, const P& b) {
        return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
    }
};

typedef vector<P> L;
P vec(L l){return l[1] - l[0];}

// 線分と点の交差判定(端点の処理に注意)(端点は含むけれども誤差に注意)
// verify : AOJ1279, AOJ2506
bool iSP(L s, P p) {return ccw(s[0], s[1], p) == 0;}

// 直線と直線の交点
// Verified: AOJ2579
// size()によって場合分け
// *4 : 直線が重なる  *1 : 交点が1つ存在 *0 : 直線が交差しない
vector<P> pLL(L l, L m){
    double A = cross(vec(l), vec(m));
    double B = cross(vec(l), l[1] - m[0]);
    if(sign(A) == 0 && sign(B) == 0) return {l[0], l[1], m[0], m[1]}; // 二直線が重なっている
    if(sign(A) == 0) return{}; // 直線が交わらない
    return {m[0] + vec(m) * B / A};
}

vector<P> pSS(L l, L m){
    vector<P> res;
    auto find = [&](P p){ 
        for(P r : res) if(sign(abs(r - p)) == 0)
                return true;
        return false;
    };
    for(P p : pLL(l, m))
        if(iSP(l,p) && iSP(m,p) && !find(p)) // 片方が直線の場合は適宜変えること
            res.push_back(p);
    return res;
}

// 入力
// ss : 線分のリスト
//
// 出力
// ps : グラフの頂点番号に対応する点が入る
// 返り値 : 上の説明のグラフ
//
// Verified
// AOJ 2113
typedef vector<int> Node;
typedef vector<Node> Graph;
Graph segment_arrangement(const vector<L> &ss, vector<P> &ps) {
    for (int i = 0; i < ss.size(); i++) {
        ps.push_back( ss[i][0] );
        ps.push_back( ss[i][1] );
        for (int j = i+1; j < ss.size(); j++){
            auto cp = pSS(ss[i], ss[j]);
            if (!cp.empty()) {
                assert(cp.size() == 1);
                ps.push_back( cp.back() );
            }
        }
    }
    sort(ps.begin(), ps.end());
    ps.erase(unique(ps.begin(), ps.end()), ps.end());

    Graph g(ps.size());
    for (int i = 0; i < ss.size(); i++) {
        vector<int> on;
        for (int j = 0; j < ps.size(); j++){
            if (iSP(ss[i], ps[j])){
                on.push_back(j);
            }
        }
        for (int j = 0; j + 1 < on.size(); j++) {
            for(int k = j + 1; k < on.size(); k++) {
                int a = on[j], b = on[k];
                g[a].push_back( b );
                g[b].push_back( a );
            }
        }
    }
    return g;
}

// 線分併合
//
// 線分のリストからオーバーラップするものたちをまとめ,新しい線分のリストを作る.
// 元々の線分のリストにおける順番は破壊される．
//
// not verified
void merge_segments(vector<L>& segs) {
    auto merge_if_able = [](L& s, L t){
        if (abs(cross(s[1]-s[0], t[1]-t[0])) > EPS) return false;
        //if (sign(cross(vec(s), vec(t))) != 0) return false;
        if (ccw(s[0], t[0], s[1]) == +1 ||
                ccw(s[0], t[0], s[1]) == -1) return false; // not on the same line
        if (ccw(s[0], s[1], t[0]) == -2 ||
                ccw(t[0], t[1], s[0]) == -2) return false; // separated
        s = { min(s[0], t[0]), max(s[1], t[1]) };
        return true;
    };
    for (int i = 0; i < segs.size(); ++i)
        if (segs[i][1] < segs[i][0])
            swap(segs[i][1], segs[i][0]);
    for (int i = 0; i < segs.size(); ++i)
        for (int j = i+1; j < segs.size(); ++j)
            if (merge_if_able(segs[i], segs[j]))
                segs[j--] = segs.back(), segs.pop_back();
}
P input() {
    double x, y;
    cin >> x >> y;
    return {x, y};
}
typedef tuple<double, int, int> T;
const int MAX = 500;
const double INF = 1e64;

int main(){
    int n;
    while(cin >> n && n > 0){
        vector<L> lines(n);
        REP(i, n) {
            P a = input();
            P b = input();
            lines[i] = {a, b};
        }

        merge_segments(lines);
        //assert(size == lines.size());

        vector<P> ps;
        Graph G = segment_arrangement(lines, ps);
        /*
        REP(i, G.size()){
            cout << i << ":";
            for(int v : G[i]) cout << v << " ";
            cout << endl;
        }
        */
        assert(ps.size() < MAX);

        REP(i, ps.size()) REP(j, i) {
            assert(abs(ps[i] - ps[j]) > EPS);
        }

        auto find = [](const vector<P>& pv, P p) -> int {
            for(int i = 0; i < pv.size(); i++) {
                auto q = pv[i];
                if(abs(p - q) < EPS) {
                    return i;
                }
            }
            return -1;
        };
        
        P sp = input();
        P gp = input();
        int s = find(ps, sp);
        int g = find(ps, gp);

        if(s == g) {
            cout << 0 << endl;
            continue;
        }

        assert(s != -1 && g != -1);

        priority_queue<T, vector<T>, greater<T>> que;
        double dist[MAX][MAX] = {};
        REP(i, MAX) REP(j, MAX) dist[i][j] = INF;
        for(int u : G[s]) {
            dist[s][u] = 0.0;
            que.push(T(0.0, s, u));
        }
        double ans = INF;
        while(!que.empty()) {
            T t = que.top(); que.pop();
            double d;
            int u, v;
            tie(d, u, v) = t;
            if(v == g) {
                ans = d;
                break;
            }
            for(int w : G[v]) if(u != w) {
                P p = ps[v] - ps[u];
                P q = ps[w] - ps[v];
                double th = abs(angle(p, q)) / M_PI * 180.0;
                double nd = d + th;
                if(dist[v][w] > nd) {
                    dist[v][w] = nd;
                    que.push(T(nd, v, w));
                }
            }
        }
        if(ans == INF) {
            cout << -1 << endl;
        } else {
            printf("%.12f\n", ans);
        }
    }

    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3368
final_rank: 4

code_snippet: #include <cstdio>
#include <map>
#include <iostream>
#include <vector>
#include <algorithm>
#include <complex>
#include <queue>
using namespace std;

static const double EPS = 1e-10;
typedef complex<double> P;
 
std::istream& operator>>(std::istream& is,P& p)
{
	is >> p.real() >> p.imag();
	return is;
}
struct L : public vector<P> {L(const P &a, const P &b) {push_back(a); push_back(b);} L(){push_back(P(0,0)); push_back(P(0,0));}};
namespace std {bool operator < (const P& a, const P& b) {return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);} }
double cross(const P& a, const P& b) {return imag(conj(a)*b);}
bool intersectLL(const L &l, const L &m) {return abs(cross(l[1]-l[0], m[1]-m[0])) > EPS || abs(cross(l[1]-l[0], m[0]-l[0])) < EPS;}
bool intersectSP(const L &s, const P &p) {return abs(s[0]-p)+abs(s[1]-p)-abs(s[1]-s[0]) < EPS;}

P crosspoint(const L &l, const L &m) {
	double A = cross(l[1] - l[0], m[1] - m[0]);
	double B = cross(l[1] - l[0], l[1] - m[0]);
	if (abs(A) < EPS && abs(B) < EPS) return m[0];
	return m[0] + B / A * (m[1] - m[0]);
}

struct Node{
	int id;
	double dir;
	double cost;
	Node(int id,double dir,double cost) : id(id),dir(dir),cost(cost){}
};
bool operator <(const Node &a,const Node &b){ return a.cost > b.cost;}

double PI = acos(-1);
//fix(x):=角度を[0,2π)の範囲にする
double fix(double x){
	while( x >= 2 * PI ) x -= 2 * PI;
	while( x < 0) x += 2 * PI;
	return x;
}
int main(){
	int n;
	while(cin >> n && n){
		L l[n];
		for(int i = 0 ; i < n ; i++) cin >> l[i][0] >> l[i][1];
		P s,g;
		cin >> s >> g;
		
		vector<P> tar,tar_; // tar:=ダイクストラで中継点/ゴール/スタートとなるであろう点の集合
		tar_.push_back(s);
		tar_.push_back(g);
		for(int i = 0 ; i < n ; i++){
			tar_.push_back(l[i][0]); 
			tar_.push_back(l[i][1]);
			for(int j = 0 ; j < n ; j++){
				if( intersectLL(l[i],l[j]) ) tar_.push_back(crosspoint(l[i],l[j]));
			}
		}
		
		// 重複点を削除する
		sort(tar_.begin(),tar_.end());
		for(int i = 0 ; i < tar_.size() ; i++)
			if( !i || abs(tar_[i-1]-tar_[i]) > EPS ) tar.push_back(tar_[i]);
		
		// 点a→点bが可能かどうかのグラフを構築
		vector< vector<int> > connect(tar.size());
		for(int i = 0 ; i < tar.size() ; i++){
			for(int j = i+1 ; j < tar.size() ; j++){
				for(int k = 0 ; k < n ; k++){
					if( intersectSP(l[k],tar[i]) && intersectSP(l[k],tar[j]) ){
						connect[i].push_back(j);
						connect[j].push_back(i);
						break;
					}
				}
			}
		}
		
		double res = -1;
		priority_queue<Node> Q;
		map< pair<int,long long> , int> done;
		for(int i = 0 ; i < tar.size() ; i++){
			if( abs(tar[i]-s) < EPS ){
				Q.push(Node(i,-114514,0)); // スタート地点を追加
				break;
			}
		}
		while( Q.size() ){
			Node q = Q.top(); Q.pop();
			//(位置,角度)で状態を持っているが，角度が誤差で無限に候補が発生するかもしれないので適当に丸めて扱う
			if( done[make_pair(q.id,(long long)(q.dir*10000))]++ ) continue;
			P my = tar[q.id];
			if( abs(my-g) < EPS ){
				res = q.cost *180/PI;
				break;
			}
			for(int i = 0 ; i < connect[q.id].size() ; i++){
				int oid = connect[q.id][i];
				P other = tar[oid] - my;
				double rad = fix(atan2(other.imag(),other.real()));
				double diff = fabs(q.dir-rad);
				diff = min(2*PI-diff,diff);
				if( q.dir == -114514 ) diff = 0;
				Q.push(Node(oid,rad,q.cost+diff));
			}
		}
		printf("%.10lf\n",res);
	}
}
accuracy: 1
time_ms: 90
memory_kb: 1440
final_rank: 10

code_snippet: #include <cstdio>
#include <map>
#include <iostream>
#include <vector>
#include <algorithm>
#include <complex>
#include <queue>
using namespace std;

static const double EPS = 1e-10;
typedef complex<double> P;
 
std::istream& operator>>(std::istream& is,P& p)
{
	is >> p.real() >> p.imag();
	return is;
}
struct L : public vector<P> {L(const P &a, const P &b) {push_back(a); push_back(b);} L(){push_back(P(0,0)); push_back(P(0,0));}};
namespace std {bool operator < (const P& a, const P& b) {return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);} }
double cross(const P& a, const P& b) {return imag(conj(a)*b);}
bool intersectLL(const L &l, const L &m) {return abs(cross(l[1]-l[0], m[1]-m[0])) > EPS || abs(cross(l[1]-l[0], m[0]-l[0])) < EPS;}
bool intersectSP(const L &s, const P &p) {return abs(s[0]-p)+abs(s[1]-p)-abs(s[1]-s[0]) < EPS;}

P crosspoint(const L &l, const L &m) {
	double A = cross(l[1] - l[0], m[1] - m[0]);
	double B = cross(l[1] - l[0], l[1] - m[0]);
	if (abs(A) < EPS && abs(B) < EPS) return m[0];
	return m[0] + B / A * (m[1] - m[0]);
}

struct Node{
	int id;
	double dir;
	double cost;
	Node(int id,double dir,double cost) : id(id),dir(dir),cost(cost){}
};
bool operator <(const Node &a,const Node &b){ return a.cost > b.cost;}

double PI = acos(-1);
//fix(x):=角度を[0,2π)の範囲にする
double fix(double x){
	while( x >= 2 * PI ) x -= 2 * PI;
	while( x < 0) x += 2 * PI;
	return x;
}
int main(){
	int n;
	while(cin >> n && n){
		L l[n];
		for(int i = 0 ; i < n ; i++) cin >> l[i][0] >> l[i][1];
		P s,g;
		cin >> s >> g;
		
		vector<P> tar,tar_; // tar:=ダイクストラで中継点/ゴール/スタートとなるであろう点の集合
		tar_.push_back(s);
		tar_.push_back(g);
		for(int i = 0 ; i < n ; i++){
			tar_.push_back(l[i][0]); 
			tar_.push_back(l[i][1]);
			for(int j = 0 ; j < n ; j++){
				if( intersectLL(l[i],l[j]) ) tar_.push_back(crosspoint(l[i],l[j]));
			}
		}
		
		// 重複点を削除する
		sort(tar_.begin(),tar_.end());
		for(int i = 0 ; i < tar_.size() ; i++)
			if( !i || abs(tar_[i-1]-tar_[i]) > EPS ) tar.push_back(tar_[i]);
		
		// 点a→点bが可能かどうかのグラフを構築
		vector< vector<int> > connect(tar.size());
		for(int i = 0 ; i < tar.size() ; i++){
			for(int j = i+1 ; j < tar.size() ; j++){
				for(int k = 0 ; k < n ; k++){
					if( intersectSP(l[k],tar[i]) && intersectSP(l[k],tar[j]) ){
						connect[i].push_back(j);
						connect[j].push_back(i);
						break;
					}
				}
			}
		}
		
		double res = -1;
		priority_queue<Node> Q;
		map< pair<int,long long> , int> done;
		for(int i = 0 ; i < tar.size() ; i++){
			if( abs(tar[i]-s) < EPS ){
				Q.push(Node(i,-114514,0)); // スタート地点を追加
				break;
			}
		}
		while( Q.size() ){
			Node q = Q.top(); Q.pop();
			//(位置,角度)で状態を持っているが，角度が誤差で無限に候補が発生するかもしれないので適当に丸めて扱う
			if( done[make_pair(q.id,(long long)(q.dir*10000000))]++ ) continue;
			P my = tar[q.id];
			if( abs(my-g) < EPS ){
				res = q.cost *180/PI;
				break;
			}
			for(int i = 0 ; i < connect[q.id].size() ; i++){
				int oid = connect[q.id][i];
				P other = tar[oid] - my;
				double rad = fix(atan2(other.imag(),other.real()));
				double diff = fabs(q.dir-rad);
				diff = min(2*PI-diff,diff);
				if( q.dir == -114514 ) diff = 0;
				Q.push(Node(oid,rad,q.cost+diff));
			}
		}
		printf("%.10lf\n",res);
	}
}
accuracy: 1
time_ms: 90
memory_kb: 1440
final_rank: 10

code_snippet: #include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cfloat>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
using namespace std;

static const double EPS = 1e-10;
const double INF = 1e12;
typedef complex<double> P,point;
 
std::istream& operator>>(std::istream& is,P& p)
{
	is >> p.real() >> p.imag();
	return is;
}

typedef vector<P> G,polygon;
struct L : public vector<P> {L(const P &a, const P &b) {push_back(a); push_back(b);} L(){push_back(P(0,0)); push_back(P(0,0));}};
namespace std {bool operator < (const P& a, const P& b) {return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);} }
double cross(const P& a, const P& b) {return imag(conj(a)*b);}
double dot(const P& a, const P& b) {return real(conj(a)*b);}

bool intersectLL(const L &l, const L &m) {return abs(cross(l[1]-l[0], m[1]-m[0])) > EPS || abs(cross(l[1]-l[0], m[0]-l[0])) < EPS;}

int ccw(P a, P b, P c) {
	b -= a; c -= a;
	if (cross(b, c) > 0)   return +1;
	if (cross(b, c) < 0)   return -1;
	if (dot(b, c) < 0) return +2;
	if (norm(b) < norm(c)) return -2;
	return 0;
}
 
 
P crosspoint(const L &l, const L &m) {
	double A = cross(l[1] - l[0], m[1] - m[0]);
	double B = cross(l[1] - l[0], l[1] - m[0]);
	if (abs(A) < EPS && abs(B) < EPS) return m[0];
	return m[0] + B / A * (m[1] - m[0]);
}
bool intersectSP(const L &s, const P &p) {return abs(s[0]-p)+abs(s[1]-p)-abs(s[1]-s[0]) < EPS;}
bool intersectSS(const L &s, const L &t) {return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0 && ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0;}

struct Node{
	int id;
	double dir;
	double cost;
	Node(int id,double dir,double cost) : id(id),dir(dir),cost(cost){}
};
bool operator <(const Node &a,const Node &b){
	return a.cost > b.cost;
}

double PI = acos(-1);
double fix(double x){
	while( x >= 2 * PI ) x -= 2 * PI;
	while( x < 0) x += 2 * PI;
	return x;
}
int main(){
	int n;
	while(cin >> n && n){
		L l[n];
		for(int i = 0 ; i < n ; i++){
			cin >> l[i][0] >> l[i][1];
		}
		vector<P> tar,tar_;
		for(int i = 0 ; i < n ; i++){
			tar.push_back(l[i][0]);
			tar.push_back(l[i][1]);
			for(int j = 0 ; j < n ; j++){
				if( intersectSS(l[i],l[j]) ) tar.push_back(crosspoint(l[i],l[j]));
			}
		}
		
		P s,g;
		cin >> s >> g;
		tar.push_back(s);
		tar.push_back(g);
		sort(tar.begin(),tar.end());
		for(int i = 0 ; i < tar.size() ; i++)
			if( !i || abs(tar[i-1]-tar[i]) > EPS ) tar_.push_back(tar[i]);
		tar = tar_;
		
		vector< vector<int> > connect(tar.size());
		for(int i = 0 ; i < tar.size() ; i++){
			for(int j = i+1 ; j < tar.size() ; j++){
				for(int k = 0 ; k < n ; k++){
					if( intersectSP(l[k],tar[i]) && intersectSP(l[k],tar[j]) ){
						connect[i].push_back(j);
						connect[j].push_back(i);
						break;
					}
				}
			}
		}
		priority_queue<Node> Q;
		for(int i = 0 ; i < tar.size() ; i++)
			if( abs(tar[i]-s) < EPS ){
				Q.push(Node(i,-114514,0));
			}
		
		map< pair<int,long long> , int> done;
		double res = -1;
		while( Q.size() ){
			Node q = Q.top(); Q.pop();
			if( done[make_pair(q.id,(long long)(q.dir*10000000))]++ ) continue;
			P my = tar[q.id];
			if( abs(my-g) < EPS ){
				res = q.cost;
				break;
			}
			for(int i = 0 ; i < connect[q.id].size() ; i++){
				int eid = connect[q.id][i];
				P ene = tar[eid];
				ene -= my;
				double rad = atan2(ene.imag(),ene.real());
				rad = fix(rad);
				double diff = fabs(q.dir-rad);
				diff = min(2*PI-diff,diff);
				
				if( q.dir == -114514 ) diff = 0;
				Q.push(Node(eid,rad,q.cost+diff));
			}
		}
		if( res < 0 ){
			cout << -1 << endl;
		}else{
			printf("%.10lf\n",res*180/PI);
		}
	}
}
accuracy: 1
time_ms: 20
memory_kb: 1440
final_rank: 3

code_snippet: #include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <complex>
#include <vector>
#include <set>
#include <queue>
using namespace std;

typedef complex<double> P;
typedef pair<P,P> L;
typedef vector<vector<vector<double> > > mat;

const int INF = 1 << 29;
const double EPS = 1e-7;

namespace std{
  bool operator == (const P &a, const P &b){
    return fabs(real(a-b)) < EPS && fabs(imag(a-b)) < EPS;
  }
}

struct data{
  P p;
  set<int> s;
  data(P p):p(p){s.clear();}
};

struct state{
  int prev,now;
  double cost;
  state(int p=0, int n=0, double c=0):prev(p),now(n),cost(c){}
  bool operator < (const state &s) const {
    return cost > s.cost;
  }
};

int n;
L l[50];
P s, g;
vector<data> v;
mat cost;


double dot(P a, P b){ return real(conj(a)*b); }

double cross(P a, P b){ return imag(conj(a)*b); }

int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return 1;
    if(cross(b,c) < -EPS) return -1;
    if(dot(b,c) < -EPS) return 2;
    if(norm(b) < norm(c)) return -2;
    return 0;
}

bool isIntersect(L s1, L s2){
    return ( ccw(s1.first,s1.second,s2.first) * ccw(s1.first,s1.second,s2.second) <= 0 &&
             ccw(s2.first,s2.second,s1.first) * ccw(s2.first,s2.second,s1.second) <= 0 );
}

P crossPoint(pair<P,P> l, pair<P,P> m){
    double A = cross(l.second - l.first, m.second - m.first);
    double B = cross(l.second - l.first, l.second - m.first);
    if(fabs(A) < EPS && fabs(B) < EPS) return m.first;
    else if(fabs(A) >= EPS) return m.first + B / A * (m.second - m.first);
}

void makeP(){
  v.clear();

  for(int i=0;i<n;i++){
    bool f=false,f2=false;
    for(int j=0;j<v.size();j++){
      if(v[j].p == l[i].first){
        v[j].s.insert(i);
        f = true;
      }
      if(v[j].p == l[i].second){
        v[j].s.insert(i);
        f2 = true;
      }
    }
    if(!f){
      v.push_back(data(l[i].first));
      v[v.size()-1].s.insert(i);
    }
    if(!f2){
      v.push_back(data(l[i].second));
      v[v.size()-1].s.insert(i);
    }

    for(int j=i+1;j<n;j++){
      if(!isIntersect(l[i],l[j])) continue;
      P p = crossPoint(l[i],l[j]);
      f = false;
      for(int k=0;k<v.size();k++){
        if(v[k].p == p){
          v[k].s.insert(i);
          v[k].s.insert(j);
          f = true;
          break;
        }
      }
      if(!f){
        v.push_back(data(p));
        v[v.size()-1].s.insert(i);
        v[v.size()-1].s.insert(j);
      }
    }
  }
}

double calcCost(P p1, P p2, P p3){
  double A = abs(p2-p3);
  double B = abs(p3-p1);
  double C = abs(p1-p2);
  return 180.0 - acos((B*B + C*C - A*A) / (2.0 * B * C)) * 180.0 / M_PI;
};

void makeCost(){
  cost.assign(v.size(), vector<vector<double> >(v.size(), vector<double>(v.size(),(double)INF)));
  for(int i=0;i<v.size();i++){
    for(int j=0;j<v.size();j++){
      if(i == j) continue;

      bool f = false;
      for(int k=0;k<n;k++){
        if(v[i].s.find(k) != v[i].s.end() && v[j].s.find(k) != v[j].s.end()){
          f = true;
          break;
        }
      }
      if(!f) continue;

      for(int k=0;k<v.size();k++){
        if(i == k || j == k) continue;

        f = false;
        for(int l=0;l<n;l++){
          if(v[k].s.find(l) != v[k].s.end() && v[j].s.find(l) != v[j].s.end()){
            f = true;
            break;
          }
        }
        if(f) cost[i][j][k] = calcCost(v[j].p, v[i].p, v[k].p);
      }
    }
  }
}

void solve(){
  priority_queue<state> Q;
  state u,u2;
  vector<vector<double> > d(v.size(), vector<double>(v.size(), (double)INF));

  if(s == g){
    cout << 0 << endl;
    return;
  }

  for(int i=0;i<v.size();i++){
    if(s == v[i].p){
      u.prev = i;
      break;
    }
  }
  for(int i=0;i<v.size();i++){
    for(set<int>::iterator it = v[u.prev].s.begin(); it != v[u.prev].s.end(); it++){
      if(i != u.prev && v[i].s.find(*it) != v[i].s.end()){
        u.now = i;
        d[u.prev][i] = 0;
        Q.push(u);
      }
    }
  }

  while(!Q.empty()){
    u = Q.top();
    Q.pop();

    if(v[u.now].p == g){
      printf("%.7f\n",u.cost);
      return;
    }

    for(int i=0;i<v.size();i++){
      u2 = state(u.now, i, d[u.prev][u.now] + cost[u.prev][u.now][i]);
      if(u2.cost < d[u.now][i]){
        d[u.now][i] = u2.cost;
        Q.push(u2);
      }
    }
  }
  cout << -1 << endl;
}

int main(){
  while(cin >> n && n){
    double x,y,x2,y2;
    for(int i=0;i<n;i++){
      double x,y,x2,y2;
      cin >> x >> y >> x2 >> y2;
      l[i] = L(P(x,y),P(x2,y2));
    }
    cin >> x >> y >> x2 >> y2;
    s = P(x,y);
    g = P(x2,y2);

    makeP();
    makeCost();
    solve();
  }
}
accuracy: 1
time_ms: 30
memory_kb: 3244
final_rank: 8

code_snippet: #include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <complex>
#include <vector>
#include <set>
#include <queue>
using namespace std;

typedef complex<double> P;
typedef pair<P,P> L;
typedef vector<vector<vector<double> > > mat;

const int INF = 1 << 29;
const double EPS = 1e-7;

namespace std{
  bool operator == (const P &a, const P &b){
    return fabs(real(a-b)) < EPS && fabs(imag(a-b)) < EPS;
  }
}

struct data{
  P p;
  set<int> s;
  data(P p):p(p){s.clear();}
};

struct state{
  int prev,now;
  double cost;
  state(int p=0, int n=0, double c=0):prev(p),now(n),cost(c){}
  bool operator < (const state &s) const {
    return cost > s.cost;
  }
};

int n;
L l[50];
P s, g;
vector<data> v;
mat cost;


double dot(P a, P b){ return real(conj(a)*b); }

double cross(P a, P b){ return imag(conj(a)*b); }

int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return 1;
    if(cross(b,c) < -EPS) return -1;
    if(dot(b,c) < -EPS) return 2;
    if(norm(b) < norm(c)) return -2;
    return 0;
}

bool isIntersect(L s1, L s2){
    return ( ccw(s1.first,s1.second,s2.first) * ccw(s1.first,s1.second,s2.second) <= 0 &&
             ccw(s2.first,s2.second,s1.first) * ccw(s2.first,s2.second,s1.second) <= 0 );
}

P crossPoint(pair<P,P> l, pair<P,P> m){
    double A = cross(l.second - l.first, m.second - m.first);
    double B = cross(l.second - l.first, l.second - m.first);
    if(fabs(A) < EPS && fabs(B) < EPS) return m.first;
    else if(fabs(A) >= EPS) return m.first + B / A * (m.second - m.first);
}

void makeP(){
  v.clear();

  for(int i=0;i<n;i++){
    bool f=false,f2=false;
    for(int j=0;j<v.size();j++){
      if(v[j].p == l[i].first){
        v[j].s.insert(i);
        f = true;
      }
      if(v[j].p == l[i].second){
        v[j].s.insert(i);
        f2 = true;
      }
    }
    if(!f){
      v.push_back(data(l[i].first));
      v[v.size()-1].s.insert(i);
    }
    if(!f2){
      v.push_back(data(l[i].second));
      v[v.size()-1].s.insert(i);
    }

    for(int j=i+1;j<n;j++){
      if(!isIntersect(l[i],l[j])) continue;
      P p = crossPoint(l[i],l[j]);
      f = false;
      for(int k=0;k<v.size();k++){
        if(v[k].p == p){
          v[k].s.insert(i);
          v[k].s.insert(j);
          f = true;
          break;
        }
      }
      if(!f){
        v.push_back(data(p));
        v[v.size()-1].s.insert(i);
        v[v.size()-1].s.insert(j);
      }
    }
  }
}

double calcCost(P p1, P p2, P p3){
  double A = abs(p2-p3);
  double B = abs(p3-p1);
  double C = abs(p1-p2);
  return 180.0 - acos((B*B + C*C - A*A) / (2.0 * B * C)) * 180.0 / M_PI;
};

void makeCost(){
  cost.assign(v.size(), vector<vector<double> >(v.size(), vector<double>(v.size(),(double)INF)));
  for(int i=0;i<v.size();i++){
    for(int j=0;j<v.size();j++){
      if(i == j) continue;

      bool f = false;
      for(int k=0;k<n;k++){
        if(v[i].s.find(k) != v[i].s.end() && v[j].s.find(k) != v[j].s.end()){
          f = true;
          break;
        }
      }
      if(!f) continue;

      for(int k=0;k<v.size();k++){
        if(i == k || j == k) continue;

        f = false;
        for(int l=0;l<n;l++){
          if(v[k].s.find(l) != v[k].s.end() && v[j].s.find(l) != v[j].s.end()){
            f = true;
            break;
          }
        }
        if(f) cost[i][j][k] = calcCost(v[j].p, v[i].p, v[k].p);
      }
    }
  }
}

void solve(){
  priority_queue<state> Q;
  state u,u2;
  vector<vector<double> > d(v.size(), vector<double>(v.size(), (double)INF));

  if(s == g){
    //cout << 0 << endl;
    //return;
  }

  for(int i=0;i<v.size();i++){
    if(s == v[i].p){
      u.prev = i;
      break;
    }
  }
  for(int i=0;i<v.size();i++){
    for(set<int>::iterator it = v[u.prev].s.begin(); it != v[u.prev].s.end(); it++){
      if(i != u.prev && v[i].s.find(*it) != v[i].s.end()){
        u.now = i;
        d[u.prev][i] = 0;
        Q.push(u);
      }
    }
  }

  while(!Q.empty()){
    u = Q.top();
    Q.pop();

    if(v[u.now].p == g){
      printf("%.7f\n",u.cost);
      return;
    }

    for(int i=0;i<v.size();i++){
      u2 = state(u.now, i, d[u.prev][u.now] + cost[u.prev][u.now][i]);
      if(u2.cost < d[u.now][i]){
        d[u.now][i] = u2.cost;
        Q.push(u2);
      }
    }
  }
  cout << -1 << endl;
}

int main(){
  while(cin >> n && n){
    double x,y,x2,y2;
    for(int i=0;i<n;i++){
      double x,y,x2,y2;
      cin >> x >> y >> x2 >> y2;
      l[i] = L(P(x,y),P(x2,y2));
    }
    cin >> x >> y >> x2 >> y2;
    s = P(x,y);
    g = P(x2,y2);

    makeP();
    makeCost();
    solve();
  }
}
accuracy: 1
time_ms: 30
memory_kb: 3244
final_rank: 8

code_snippet: #include<iostream>
#include<sstream>
#include<algorithm>
#include<set>
#include<map>
#include<queue>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iomanip>

#define rep(i,n) for(int i=0;i<(int)n;i++)
#define all(c) (c).begin(),(c).end()
#define mp make_pair
#define pb push_back
#define each(i,c) for(__typeof((c).begin()) i=(c).begin();i!=(c).end();i++)
#define dbg(x) cerr<<__LINE__<<": "<<#x<<" = "<<(x)<<endl
#define F first
#define S second
using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef pair<int,int> pi;
const int inf = (int)1e9;
const double EPS = 1e-8, INF = 1e12, PI = acos(-1.0);
typedef complex<long double> P;
namespace std{
	bool operator<(const P& a, const P& b){
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
	bool operator==(const P &a, const P &b){
		return abs(a - b) < EPS;
	}
}
inline double cross(const P& a, const P& b){ return imag(conj(a)*b); }
inline double dot(const P& a, const P& b){ return real(conj(a)*b); }
struct L : public vector<P>{
	L(const P &a, const P &b) {
		push_back(a); push_back(b);
	}
};
typedef vector<P> G;

inline int ccw(P a, P b, P c) {
	b -= a; c -= a;
	if(cross(b, c) > EPS)   return +1;		// counter clockwise
	if(cross(b, c) < -EPS)   return -1;		// clockwise
	if(dot(b, c) < -EPS)     return +2;		// c--a--b on line
	if(norm(b) + EPS < norm(c)) return -2;		// a--b--c on line
	return 0;
}
bool intersectSS(const L &s, const L &t) {
  return ccw(s[0],s[1],t[0])*ccw(s[0],s[1],t[1]) <= 0 &&
         ccw(t[0],t[1],s[0])*ccw(t[0],t[1],s[1]) <= 0;
}
P crosspoint(const L &l, const L &m) {
  long double A = cross(l[1] - l[0], m[1] - m[0]);
  long double B = cross(l[1] - l[0], l[1] - m[0]);
  if (abs(A) < EPS && abs(B) < EPS) return m[0]; // same line
  if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
  return m[0] + B / A * (m[1] - m[0]);
}
int n;
vector<vi> e;

int main(){
	while(cin >> n, n){
		vector<L> ls;
		P s, t;
		rep(i, n){
			int x, y, X, Y;
			cin >> x >> y >> X >> Y;
			ls.pb(L(P(x, y), P(X, Y)));
			if(ls[i][1] < ls[i][0]) swap(ls[i][0], ls[i][1]);
		}
		cin >> s.real() >> s.imag() >> t.real() >> t.imag();
		
		bool er[50] = {};
		while(1){
			bool update = 0;
			rep(i, n) if(!er[i]) rep(j, i) if(!er[j]){
				if(abs(cross(ls[i][0] - ls[i][1], ls[j][0] - ls[j][1])) > EPS) continue;
				bool ok = 0;
				rep(k, 2) rep(l, 2){
					if(ccw(ls[k ? i : j][l], ls[k ? j : i][0], ls[k ? j : i][1]) == 2) ok = 1;
					if(ls[i][k] == ls[j][l]) ok = 1;
				}
				if(!ok) continue;
				
				ls[i][0] = min(ls[i][0], ls[j][0]);
				ls[i][1] = max(ls[i][1], ls[j][1]);
				er[j] = 1;
			}
			if(!update) break;
		}
		vector<L> tmp;
		rep(i, n) if(!er[i]) tmp.pb(ls[i]);
		ls = tmp;
		
		n = ls.size();
		map<P, int> id;
		G ps;
		rep(i, n) rep(j, i) if(intersectSS(ls[i], ls[j])){
			P p = crosspoint(ls[i], ls[j]);
			if(!id.count(p)) id[p] = ps.size(), ps.pb(p);
		}
		if(!id.count(s)) id[s] = ps.size(), ps.pb(s);
		if(!id.count(t)) id[t] = ps.size(), ps.pb(t);
		
		int m = ps.size();
		e.clear(); e.resize(m);
		rep(i, n){
			vi v;
			rep(j, m) if(ps[j] == ls[i][0] || ps[j] == ls[i][1] ||
				ccw(ps[j], ls[i][0], ls[i][1]) == 2) v.pb(j);
			rep(j, v.size()) rep(k, j) e[v[j]].pb(v[k]), e[v[k]].pb(v[j]);
		}
		
		set<pi> v;
		priority_queue<pair<long double, pi> > q;
		each(i, e[id[s]]){
			q.push(mp(0, mp(*i, id[s])));
		}
		while(!q.empty()){
			int c = q.top().S.F, p = q.top().S.S;
			long double co = q.top().F;
			q.pop();
			if(v.count(mp(c, p))) continue;
			v.insert(mp(c, p));
			if(ps[c] == t){
				cout << fixed << setprecision(20) << -co * 180 / PI << endl;
				goto END;
			}
			
			each(i, e[c]) if(ps[*i] != ps[c] && !v.count(mp(*i, c))){
				long double a = arg((ps[*i] - ps[c]) / (ps[c] - ps[p]));
				q.push(mp(co - abs(a), mp(*i, c)));
			}
		}
		cout << "-1" << endl; END:;
	}
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1436
final_rank: 1

code_snippet: #include<complex>
#include<vector>
#include<set>
#include<iostream>
#include<stack>
#include<cmath>
#include<queue>

#define FRONT 0x01
#define RIGHT 0x02
#define BACK 0x04
#define LEFT 0x08
#define OVER 0x10

#define CIRCLE_SAME 0x01
#define CIRCLE_CONTAIN 0x02
#define CIRCLE_NO_CROSS 0x04
#define CIRCLE_ONE_CROSS 0x08
#define CIRCLE_ONE_INSIDE_CROSS 0x10
#define CIRCLE_TWO_CROSS 0x20

#define sc second
#define fr first

#define REP(i,n) for(int i = 0; i < (int)(n); ++i)

using namespace std;

typedef double elem;
typedef complex<elem> point, vec;
typedef pair<point, point> line, hline, seg, pp;

const double eps = 1.0e-6;
const double pi = acos(-1.0);
const double infty = 1e40;
point base(0,0);

// oÍ
ostream &operator<<(ostream &os, const pair<point,point> &p){
  os << p.fr << "-" << p.sc;
  return os;
}

// lZ
inline elem sq(elem a){ return a*a; }
inline elem cq(elem a){ return a*a*a; }

// pxÏ·
elem rad(elem deg){ return (deg/180)*pi; }
elem deg(elem rad){ return (rad*180)/pi; }

// ®¬_Ìô¢AÈÇ
bool eq(elem a, elem b){ return abs(a-b) < eps; }
bool lt(elem a, elem b){ return !eq(a,b) && a < b; }
bool leq(elem a, elem b){ return eq(a,b) || a < b; }
bool gt(elem a, elem b){ return !eq(a,b) && a > b; }
bool geq(elem a, elem b){ return eq(a,b) || a > b; }
bool ltz(elem a){ return lt( a, 0 ); }
bool gtz(elem a){ return gt( a, 0 ); }
bool eqv(vec a, vec b){ return eq( abs(b-a),0); }
bool is_zv(vec v){ return eq(abs(v),0); }
elem emax(elem a, elem b){ return gt(a,b)?a:b; }
elem emin(elem a, elem b){ return lt(a,b)?a:b; }

// _Iy[^
bool far(point a, point b){ return gtz( abs(b-a) ); }
bool near(point a, point b){ return leq( abs(b-a), 0 ); }
elem dot(vec a, vec b){ return (a.real() * b.real() + a.imag() * b.imag() ); }
elem cross(vec a, vec b){ return ( a.real() * b.imag() - a.imag() * b.real() ); }

// a©çbÜÅvñèÌpxAàpA]ñ]
elem varg(vec a, vec b){
  elem ret=arg(a)-arg(b);
  if(lt(ret,0))ret+=2*pi;
  if(gt(ret,2*pi))ret-=2*pi;
  if(eq(ret,2*pi))ret=0;
  return ret;
}
elem arg(vec a, vec b){ return acos( dot(a,b) / ( abs(a) * abs(b) ) ); }
point rot(point p, elem theta){ return p * polar((elem)1.0, theta); }
point rotdeg(point p, elem deg){ return p * polar((elem)1.0, rad(deg)); }
point proj(line l, point p){
  double t=dot(p-l.first,l.first-l.second)/abs(l.first-l.second);
  return l.first + t*(l.first-l.second);
}
point reflect(line l, point p){ return p+2.0*(proj(l,p)-p); }

// ñ_Ô£A¼üÆ_ÌÅZ£AüªÆ_ÌÅZ£
elem dist(point a, point b){ return abs(a-b); }
elem dist_l(line l, point x){ return abs(cross(l.sc-l.fr,x-l.fr)) / abs(l.sc-l.fr); }
elem dist_seg(seg s, point x)
{
  if( ltz( dot(s.sc-s.fr,x-s.fr) ) ) return abs(x-s.fr);
  if( ltz( dot(s.fr-s.sc,x-s.sc) ) ) return abs(x-s.sc);
  return dist_l(s,x);
}

// PÊxNgA@üxNgAPÊ@üxNg
vec uvec(vec a){ return a / abs(a); }
vec nmr(vec a){ return a * vec(0,-1); }
vec nml(vec a){ return a * vec(0,1); }
vec unmr(vec a){ return uvec( nmr(a) ); }
vec unml(vec a){ return uvec( nml(a) ); }

// ¼ðA½s»è
bool orth(point a1, point a2, point b1, point b2){ return eq( dot( a2 - a1, b2 - b1 ), 0 ); }
bool orth(vec v1, vec v2){ return eq( dot(v1, v2), 0 ); }
bool prll(point a1, point a2, point b1, point b2){ return eq( cross( a2 - a1, b2 - b1 ), 0 ); }
bool prll(vec v1, vec v2){ return eq( cross(v1, v2), 0 ); }

// CCW oXg¾ªA¸xÉæé
int ccw(point a, point b, point x){
  b -= a;
  x -= a;
  // if( is_zv(b) || is_zv( x ) ) return ERROR;
  if( gtz( cross(b,x) ) ) return LEFT;
  if( ltz( cross(b,x) ) ) return RIGHT;
  if( ltz( dot(b,x) ) ) return BACK;
  if( lt( abs(b), abs(x) ) ) return FRONT;
  return OVER;
}

// üªÌð·»è
bool intersectedSS(seg a, seg b)
{
  if( ccw(a.fr,a.sc,b.fr)&OVER || ccw(a.fr,a.sc,b.sc)&OVER ) return true;
  return
    ( ccw(a.fr,a.sc,b.fr) | ccw(a.fr,a.sc,b.sc) ) == (LEFT|RIGHT) &&
    ( ccw(b.fr,b.sc,a.fr) | ccw(b.fr,b.sc,a.sc) ) == (LEFT|RIGHT) ;
}
// ¼üÌð·»è
bool intersectedLL(line a, line b){ return !eq( cross(a.sc-a.fr,b.sc-b.fr), 0.0 ); }

// ð_vZ
point intersectionSS(seg a, seg b)
{
  elem d1 = dist_l(b,a.fr);
  elem d2 = dist_l(b,a.sc);
  return a.fr + ( d1 / (d1 + d2 ) ) * (a.sc-a.fr);
}
point intersectionLL(line a, line b)
{
  vec va = a.sc - a.fr;
  vec vb = b.sc - b.fr;
  return a.fr + va * ( cross(vb, b.fr - a.fr) / cross(vb,va) );
}

// üªð_êÅ
bool intersectionLL(line a, line b, point &ret){
  return intersectedLL( a, b ) ? ret = intersectionLL( a, b ), true : false;
}
bool intersectionLH(line a, hline b, point &ret){
  point tmp;
  return intersectionLL(a,b,tmp) ? ( ccw(b.fr,b.sc,tmp)&(OVER|FRONT) ? ret=tmp, true : false ) : false;
}
bool intersectionLS(line l, seg s, point &ret){
  point tmp;
  return intersectionLL(l,s,tmp) ? ( ccw(s.fr,s.sc,tmp)&OVER ? ret=tmp, true : false ) : false;
}
bool intersectionHH(hline a, hline b, point &ret){
  point tmp;
  return intersectionLL(a,b,tmp) ? ( ccw(a.fr,a.sc,tmp)&(OVER|FRONT)&&ccw(b.fr,b.sc,tmp)&(OVER|FRONT) ? ret = tmp, true : false ) : false;
}
bool intersectionHS(hline a, seg s, point &ret){
  point tmp;
  return intersectionLS(a,s,tmp) ? ( ccw(a.fr,a.sc,tmp)&(OVER|FRONT) ? ret = tmp, true : false ) : false;
}
bool intersectionSS(seg a, seg b, point &ret){
  return intersectedSS(a,b) ? ret = intersectionSS(a,b), true : false;
}

struct Node{
  point p;
  vector<int> con;
  Node(){}
  Node(point p):p(p){}
};

typedef vector<Node> Graph;

struct State{
  int prev;
  int now;
  double cost;
  State(int prev, int now, double cost):prev(prev),now(now),cost(cost){}
  bool operator>(const State &t)const{
    return cost > t.cost;
  }
};

double weight(int pre, int now, int next, const Graph &G){
  if( now == 0 ) return 0;
  vec a(G[now].p-G[pre].p);
  vec b(G[next].p-G[now].p);
  double ret = varg( a, b );
  // assert(ret>=0);
  return gt(ret,pi)?2*pi-ret:ret;
}

double dijkstra(int st, const Graph &G){
  double ret = infty;
  priority_queue< State, vector<State>, greater<State> > pq;
  bool vis[G.size()+1][G.size()];
  double C[G.size()+1][G.size()];
  for(int i = 0; i < G.size()+1; ++i){
    for(int j = 0; j < G.size(); ++j){
      vis[i][j]=false;
      C[i][j]=infty;
    }
  }
  
  pq.push( State(G.size(),st,0.0) );
  C[G.size()][st]=0;
  while(!pq.empty()){
    State now = pq.top(); pq.pop();
    
    //cout << " PREV : " <<  now.prev << " NOW : " << now.now << " COST : " << now.cost << endl;
    vis[now.prev][now.now] = false;
    
    /*
    if( vis[ now.prev ][ now.now ] ) continue;
    else{
      vis[ now.prev ][ now.now ] =true;
      if( now.now == 1 ){
	//ret = emin( ret, now.cost );
	continue;
      }
    }
    */
    
    const vector<int> &con = G[now.now].con;
    for(int i = 0; i < con.size(); ++i){
      int nextid = con[i];
      double newcost = now.cost + weight(now.prev, now.now, nextid, G);
      if( lt( newcost, C[now.now][nextid] ) ){
	C[now.now][nextid] = newcost;
	if( !vis[now.now][nextid] ){
	  vis[now.now][nextid]=true;
	  State next( now.now, nextid, newcost );
	  pq.push( next );
	}
      }
    }
    
  }

  for(int i = 0; i < G.size()+1; ++i){
    ret = emin( ret, C[i][1] );
  }
  return ret;
}

struct Point{
  point p;
  bool operator<(const Point &t)const{
    return eq(p.real(),t.p.real()) ? lt( p.imag(), t.p.imag() ) : lt(p.real(),t.p.real());
  }
  Point ():p(0,0){}
  Point (point p):p(p){}
};

int main(){
  while(true){
    int n;
    cin >> n;
    if ( n == 0 ) break;
    Graph G;
    set<Point> exist_intersection;
    vector<seg> segs;
    
    for(int i = 0; i < n; ++i){
      elem x1,y1,x2,y2;
      cin >> x1 >> y1 >> x2 >> y2;
      segs.push_back( seg(point(x1,y1),point(x2,y2)) );
    }

    elem sx,sy,gx,gy;cin>>sx>>sy>>gx>>gy;
    G.push_back(point(sx,sy));
    exist_intersection.insert( Point(point(sx,sy)) );
    if(exist_intersection.find(Point(point(gx,gy)))==exist_intersection.end()){
      G.push_back(point(gx,gy));
      exist_intersection.insert(Point(point(gx,gy)));
    }else{
      printf("0.0\n");continue;
    }

    for(int i = 0; i < segs.size(); ++i){
      if( exist_intersection.find(Point(segs[i].fr))==exist_intersection.end()){
	exist_intersection.insert(Point(segs[i].fr));
	G.push_back( segs[i].fr );
      }
      if( exist_intersection.find(Point(segs[i].sc))==exist_intersection.end()){
	exist_intersection.insert(Point(segs[i].sc));
	G.push_back( segs[i].sc );
      }
      for(int j = 0; j < segs.size(); ++j){
	if( i != j ){
	  point tmp;
	  if( intersectionSS( segs[i], segs[j], tmp ) ){
	    if( exist_intersection.find(Point(tmp)) == exist_intersection.end() ){
	      exist_intersection.insert( Point(tmp) );
	      G.push_back( Node(tmp) );
	    }
	  }
	}
      }
    }

    for(int i = 0; i < segs.size(); ++i){
      for(int j = 0; j < G.size(); ++j){
	for(int k = 0; k < G.size(); ++k){
	  if( j != k ){
	    if( ccw( segs[i].fr, segs[i].sc, G[j].p ) == OVER &&
		ccw( segs[i].fr, segs[i].sc, G[k].p ) == OVER ){
	      //cout << G[j].p << ' ' << G[k].p << endl;
	      G[j].con.push_back( k );
	      G[k].con.push_back( j );
	    }
	  }
	}
      }
    }
    
    elem ans = deg( dijkstra( 0, G ) );
    if( geq( ans, infty ) ){
      printf("-1\n");
    }else{
      printf("%.11lf\n",ans);
    }
    
  }
  return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 0
final_rank: 2

code_snippet: #include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<complex>
#include<cmath>
using namespace std;

#define REP(i,N) for(int i=0;i<(int)(N);++i)
#define ALL(v) (v).begin(),(v).end()

typedef complex<double> P;
const double EPS = 1e-10;
const double PI = 4.0 * atan2(1, 1);

namespace std {
  bool operator < (const P& a, const P& b) {
    return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
  }
}

inline double dot(P a, P b) {return real( conj(a)*b);}
inline double cross(P a, P b) {return imag( conj(a)*b);}
int ccw(P a, P b, P c) {
  b -= a; c -= a;
  if (cross(b, c) > EPS)   return +1;       // counter clockwise
  if (cross(b, c) < -EPS)   return -1;       // clockwise
  if (dot(b, c) < -EPS)     return +2;       // c--a--b on line
  if (norm(b) + EPS < norm(c)) return -2;       // a--b--c on line
  return 0;
}

bool IsIntersectSS(P a1, P a2, P b1, P b2) {
  return ccw(a1,a2,b1) * ccw(a1,a2,b2) <= 0 &&
    ccw(b1,b2,a1) * ccw(b1,b2,a2) <= 0;
}

bool IsIntersectSP(P a, P b, P c) {
  return (abs(a-c) + abs(c-b) < abs(a-b) + EPS);
}

P IntersectionLL(P a1,P a2,P b1, P b2) {
  double A = cross(b2 - b1, a2 - a1);
  double B = cross(b2 - b1, b2 - a1);
  if (abs(A) < EPS && abs(B) < EPS) return a1; // same line
//  if (abs(A) < EPS) assert(false); // !!!PRECONDITION NOT SATISFIED!!!
  return a1 + B / A * (a2 - a1);
}

typedef vector<vector<int> > Graph;

Graph Arrangement(const vector<P> &from, const vector<P> &to, vector<P> &ps) {
  REP(i, from.size()) {
    ps.push_back( from[i] );
    ps.push_back( to[i] );
    REP(j, i) {
      if( IsIntersectSS( from[i], to[i], from[j], to[j]) )
        ps.push_back( IntersectionLL(from[i], to[i], from[j], to[j]));
    }
  }
  sort(ALL(ps));
  ps.erase(unique(ALL(ps)), ps.end());
  Graph g(ps.size());

  REP(i, from.size()) {
    vector< pair<double, int> > onlines;
    REP(j, ps.size()) {
      if( IsIntersectSP(from[i], to[i], ps[j]) )
        onlines.push_back( make_pair(norm(from[i] - ps[j]), j) );
    }
    sort( ALL(onlines) );
    for(int j = 0; j + 1 < onlines.size(); j++) {
      int a = onlines[j].second;
      int b = onlines[j+1].second;
      g[a].push_back(b);
      g[b].push_back(a);
    }
  }
  return g;
}

double memo[1024][1024];
struct State {
  int pos, prev;
  double cost;

  bool operator<(const State& t) const {
    return cost > t.cost;
  }
  double &ref() {
    return memo[pos][prev];
  }
};

int indexOf(const vector<P>& ps, P p) {
  REP(i, ps.size()) {
    if( norm( ps[i] - p ) < EPS )
      return i;
  }
  return -1;
}

double Arg(P a, P b, P c) {
  if( norm(b - a) < EPS ) return 0;
//   if( ccw(a, b, c) == 2 || ccw(a, b, c) == 0 ) {return 0;}
  double theta = arg( (c - b) / (b - a) );
  theta = abs(theta);
//   if( dot( b - a, c - b) < -EPS ) theta += PI / 2;
  return theta;
}

double solve(Graph &g, vector<P> &ps, int si, int gi) {
  REP(i, 1024) REP(j, 1024) memo[i][j] = 1e10;

  priority_queue< State > up;

  State s = (State){si, si,0};
  up.push(s);
  s.ref() = 0;
  while( !up.empty() ) {
    s = up.top(); up.pop();

    if( s.pos == gi )
      return s.cost;

    for(int i = 0; i < g[s.pos].size(); i++) {
      State next = s;
      next.pos = g[s.pos][i];
      next.prev = s.pos;
      next.cost += Arg( ps[s.prev], ps[s.pos], ps[next.pos] );
      if( next.ref() > next.cost + EPS ) {
        next.ref() = next.cost;
        up.push( next );
      }
    }
  }
  return -1;
}

int main() {
  for(;;) {
    int N; scanf("%d", &N);
    if( N == 0 ) break;
    vector<P> from, to;
    REP(i, N) {
      int a, b, c, d;
      scanf("%d%d%d%d", &a, &b, &c, &d);
      from.push_back( P(a, b) );
      to.push_back( P(c, d) );
    }
    int a, b, c, d;
    scanf("%d%d%d%d", &a, &b, &c, &d);
    P start(a, b);
    P goal(c, d);

    vector<P> ps;
    Graph g = Arrangement(from, to, ps);

    int si = indexOf( ps, start );
    int gi = indexOf( ps, goal );
    
    double rad = solve(g, ps, si, gi);
    if( rad < -0.5 ) {
      cout << -1 << endl;
    } else {
      printf("%.8f\n", rad * 180  / PI);
    }
  }
}
accuracy: 1
time_ms: 140
memory_kb: 9228
final_rank: 14