Problem:
Problem L: RedBlue
Story
天空都市AIZUのUZIA高校では、競技プログラミングの部活動がとても盛んである。
この部活には、
n
人のRed Coderと
n
人のBlue Coderが所属している。
ある日の部活の時間に、Red CoderとBlue Coderでペアを組み、この部活から
n
組、KCPというコンテストに参加することとなった。この高校では、ペアを組む学生同士は握手するという習わしがあるので、部員たちは今すぐ自分のパートナーを見つけることにした。
部員たちは全速力で走るため、まっすぐにしか進めない。また、部員たちは、それぞれの部員が移動する距離の総和をできるだけ小さくしたいと思っている。
なお、部室には2つの円形のテーブルが置いてある。
Problem
二次元平面上に2つの円、
n
個の赤色の点、
n
個の青色の点がある。
2つの円の中心座標はそれぞれ(
x
1
,
y
1
), (
x
2
,
y
2
)であり、半径はそれぞれ
r
1
,
r
2
である。
赤い点
i
は、座標(
rx
i
,
ry
i
)にあり、青い点
j
は、座標(
bx
j
,
by
j
)にある。
あなたは、以下の操作を
n
回繰り返す必要がある。
まだ選ばれていない点の中から、赤色の点と青色の点を１つずつ選んで、2点の共通の目的地を設定し、その目的地に向かって2点をそれぞれまっすぐ移動させる。
目的地は二次元平面上であれば、どこに設定しても構わない。ただし、選んだ2点は移動の際に円の内部を通過することはできないので、そのような移動が発生する目的地を設定することはできない。
n
回の操作をしたときの移動距離の総和を最小化せよ。
n
回の操作を行えない場合は、代わりに"Impossible" (""は除く) と出力せよ。
Input
入力は以下の形式で与えられる。
n
x
1
y
1
r
1
x
2
y
2
r
2
rx
1
ry
1
rx
2
ry
2
...
rx
n
ry
n
bx
1
by
1
bx
2
by
2
...
bx
n
by
n
入力は全て整数で与えられる。
1行目に
n
が与えられる。
2行目に
x
1
,
y
1
,
r
1
が空白区切りで与えられる。
3行目に
x
2
,
y
2
,
r
2
が空白区切りで与えられる。
4から3+
n
行に赤い点の座標(
rx
i
,
ry
i
)が空白区切りで与えられる。
4+
n
から3+2×
n
行に青い点の座標(
bx
j
,
by
j
)が空白区切りで与えられる。
Constraints
入力は以下の条件を満たす。
1 ≤
n
≤ 100
-1000 ≤
x
i
,
y
i
≤ 1000
1 ≤
r
i
≤ 50
-1000 ≤
rx
i
,
ry
i
,
bx
i
,
by
i
≤ 1000
同じ座標に複数の点が存在していることはない
任意の円の半径を絶対値10
-9
以内で変化させても、高々絶対値10
-3
しか変化しない
任意の円の半径を絶対値10
-9
以内で変化させても、"Impossible"なケースは"Impossible"のままである
解は10000を超えない
どの点も、円から10
-3
以上離れていて、点が円周上に存在したり、点が円に内包されることはない
2つの円は共通面積を持たず、10
-3
以上離れていることが保証される
Output
n
回の操作をしたときの移動距離の総和の最小値を1行に出力せよ。なお、出力はジャッジ解の出力との絶対誤差が10
-2
以内であれば許容される。
n
回の操作を行えない場合は、代わりに"Impossible" (""は除く) と出力せよ。
Sample Input 1
2
3 3 2
8 3 2
0 3
3 7
8 0
8 7
Sample Output 1
13.8190642862
Sample Input 2
2
3 3 2
8 3 2
3 0
3 7
8 0
8 7
Sample Output 2
10.0000000000
Sample Input 3
2
3 3 2
8 3 2
0 0
0 5
11 0
11 5
Sample Output 3
22.0000000000
Sample Input 4
1
10 10 10
31 10 10
15 19
26 1
Sample Output 4
Impossible
点同士をつなぐことはできません。

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LD;
const int N = 205;
const int M = 100005;
const LD INF = 1e18;
const LD eps = 1e-10;

inline int sgn(LD x) {
    return x > eps? 1 : x < -eps? -1 : 0;
}

struct Point {
    LD x, y;
    Point(LD _x = 0, LD _y = 0): x(_x), y(_y) {}
    bool operator == (const Point &rhs) const {
        return sgn(x - rhs.x) == 0 && sgn(y - rhs.y) == 0;
    }
    Point operator + (const Point &rhs) const {
        return Point(x + rhs.x, y + rhs.y);
    }
    Point operator - (const Point &rhs) const {
        return Point(x - rhs.x, y - rhs.y);
    }
    Point operator * (const LD &rhs) const {
        return Point(x * rhs, y * rhs);
    }
    Point operator / (const LD &rhs) const {
        return Point(x / rhs, y / rhs);
    }
    LD operator * (const Point &rhs) const {
        return x * rhs.x + y * rhs.y;
    }
    LD operator ^ (const Point &rhs) const {
        return x * rhs.y - y * rhs.x;
    }
    LD len2() {
        return x * x + y * y;
    }
    LD len() {
        return sqrtl(len2());
    }
    Point unit() {
        return (*this) / len();
    }
    Point rotate(LD ang) {
        return Point(x * cos(ang) - y * sin(ang), x * sin(ang) + y * cos(ang));
    }
} a[N], b[N];

struct Circle {
    Point c;
    LD r;
    Circle(Point _c = (0, 0), LD _r = 0): c(_c), r(_r) {}
} C[2];
vector<Point> ta[N], tb[N];

Point LineInter(Point u1, Point v1, Point u2, Point v2) {
    LD a1 = (v2 - u2) ^ (u1 - u2), a2 = (v2 - u2) ^ (v1 - u2);
    return (u1 * a2 - v1 * a1) / (a2 - a1);
}

Point PointProjLine(Point p, Point u, Point v) {
    Point dir = (v - u).unit();
    return u + dir * (dir * (p - u));
}

LD PointLineDist(Point p, Point u, Point v) {
    Point dir = (v - u).unit();
    return fabsl(dir ^ (p - u));
}

bool Onseg(Point p, Point u, Point v) {
    if (sgn((p - u) ^ (v - u)) == 0 && sgn((p - u) * (p - v)) <= 0) return 1;
    return 0;
}

LD PointSegDist(Point p, Point u, Point v) {
    Point o = PointProjLine(p, u, v);
    if (Onseg(o, u, v)) return (p - o).len();
    return min((p - u).len(), (p - v).len());
}

bool SegCircleIntersect(Point u, Point v, Circle c) {
    return sgn(PointSegDist(c.c, u, v) - c.r) < 0;
}

vector<Point> Tangents(Point p) {
    vector<Point> ret;
    for (int i = 0; i < 2; ++i) {
        LD delta = acosl(C[i].r / (p - C[i].c).len());
        Point m = (p - C[i].c).unit() * C[i].r;
        ret.push_back(C[i].c + m.rotate(delta));
        ret.push_back(C[i].c + m.rotate(-delta));
    }
    return ret;
}

LD Meet(int i, int j) {
    if (!SegCircleIntersect(a[i], b[j], C[0]) && 
        !SegCircleIntersect(a[i], b[j], C[1])) {
        return (a[i] - b[j]).len(); //go directly
    }
    LD ret = INF;
    for (auto u : ta[i]) {
        for (auto v : tb[j]) {
            if (sgn((u - a[i]) ^ (v - b[j])) == 0) continue; //parallel
            Point w = LineInter(a[i], u, b[j], v);
            if (SegCircleIntersect(a[i], w, C[0])) continue;
            if (SegCircleIntersect(a[i], w, C[1])) continue;
            if (SegCircleIntersect(b[j], w, C[0])) continue;
            if (SegCircleIntersect(b[j], w, C[1])) continue;
            ret = min(ret, (w - a[i]).len() + (w - b[j]).len());
        }
    }
    return ret;
}

struct CostFlow {
    int n, S, T, maxflow, inq[N], pre[N];
    LD mincost, dis[N];
    
    struct Edge {
        int v, w, nxt;
        LD c;
    } e[M << 1];
    int first[N], eCnt;

    inline void AddEdge(int u, int v, int w, LD c) {
        e[++eCnt].v = v;
        e[eCnt].w = w;
        e[eCnt].c = c;
        e[eCnt].nxt = first[u];
        first[u] = eCnt;
    }

    inline void Add(int u, int v, int w, LD c) {
        AddEdge(u, v, w, c);
        AddEdge(v, u, 0, -c);
    }

    void Init(int _n) {
        n = _n;
        mincost = maxflow = 0;
        for (int i = 1; i <= n; ++i) {
            first[i] = 0;
        }
        eCnt = 1;
    }

    bool SPFA() {
        for (int i = 1; i <= n; ++i) {
            dis[i] = INF;
            pre[i] = 0;
        }
        dis[S] = 0;
        queue<int> q;
        q.push(S);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            inq[u] = 0;
            for (int i = first[u]; i; i = e[i].nxt) {
                int v = e[i].v;
                if (e[i].w > 0 && dis[v] > dis[u] + e[i].c + eps) {
                    dis[v] = dis[u] + e[i].c;
                    pre[v] = i;
                    if (!inq[v]) {
                        q.push(v);
                        inq[v] = 1;
                    }
                }
            }
        }
        return (dis[T] < INF / 2);
    }

    void Augment() {
        for (int i = pre[T]; i; i = pre[e[i ^ 1].v]) {
            e[i].w -= 1;
            e[i ^ 1].w += 1;
        }
        maxflow += 1;
        mincost += dis[T];
    }

    void MCMF(int s, int t) {
        S = s; T = t;
        while (SPFA()) {
            Augment();
        }
    }
} Flow;

void solve() {
    int n;
    scanf("%d", &n);
    for (int i = 0; i < 2; ++i) {
        scanf("%Lf %Lf %Lf", &C[i].c.x, &C[i].c.y, &C[i].r);
    }
    for (int i = 1; i <= n; ++i) {
        scanf("%Lf %Lf", &a[i].x, &a[i].y);
        ta[i] = Tangents(a[i]);
    }
    for (int i = 1; i <= n; ++i) {
        scanf("%Lf %Lf", &b[i].x, &b[i].y);
        tb[i] = Tangents(b[i]);
    }
    int S = n * 2 + 1, T = S + 1;
    Flow.Init(T);
    for (int i = 1; i <= n; ++i) {
        Flow.Add(S, i, 1, 0);
        Flow.Add(n + i, T, 1, 0);
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            LD dis = Meet(i, j);
            if (dis < INF / 2) {
//printf("%d %d %.10Lf\n", i, j, dis);
                Flow.Add(i, n + j, 1, dis);
            }
        }
    }
    Flow.MCMF(S, T);
    if (Flow.maxflow != n) {
        puts("Impossible");
        return;
    }
    printf("%.10Lf\n", Flow.mincost);
}

int main() {
    solve();
    return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 4692
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
const double EPS = 1e-5,INF = 1e12;
typedef complex<double> P;
typedef pair<P,P> L;
struct C{P p;double r;};
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);}
P proj(P p, L l){
  return l.first + dot(p - l.first, l.second - l.first) / norm(l.second - l.first) * (l.second - l.first);
}
double D(P a, P b) {
  return sqrt((a.real()-b.real())*(a.real()-b.real())+(a.imag()-b.imag())*(a.imag()-b.imag()));
}
bool intersectSP(const L &s, const P &p) {return abs(s.first-p)+abs(s.second-p)-abs(s.second-s.first) < EPS;}
bool intersectLL(const L &l, const L &m) {
  return abs(cross(l.second-l.first, m.second-m.first)) > EPS ||
         abs(cross(l.second-l.first, m.first-l.first)) < EPS;
}
P crosspoint(const L &l, const L &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;
  if (fabs(A) < EPS) assert(false);
  return m.first + B / A * (m.second - m.first);
}
vector<P> getIntersectCS(C c, L s){
  vector<P> res;
  P h = proj(c.p, s);
  double d = abs(c.p - h);
  if(d > c.r + EPS);
  else if(d > c.r - EPS){
    if(intersectSP(s,h)) res.push_back(h);
  }
  else {
    P v = s.second - s.first;
    v = (sqrt(c.r*c.r - d*d) / abs(v)) * v;
    if(intersectSP(s,h+v)) res.push_back(h+v);
    if(intersectSP(s,h-v)) res.push_back(h-v);
  }
  return res;
}
double toRad(double agl) {return agl*M_PI/180.0;}
P rotate(P a, double r){return P(a.real()*cos(r)-a.imag()*sin(r),a.real()*sin(r)+a.imag()*cos(r));}
vector<P> tangent(C c, P q){
  vector<P> res;
  double a = abs(q - c.p);
  if(a < c.r - EPS);
  else if(a < c.r + EPS) res.push_back(rotate(c.p-q,toRad(90))+q);
  else {
    double b = sqrt(a*a-c.r*c.r);
    double psi = arg(q - c.p);
    double phi = M_PI - acos(b/a);
    res.push_back(q + b * P(cos(psi+phi), sin(psi+phi)));
    res.push_back(q + b * P(cos(psi-phi), sin(psi-phi)));
  }
  return res;
}
const int MAX_V= 1002;
struct edge{
  int to,cap,rev;
  double cost;
  edge(int to,int cap,double cost,int rev) :to(to),cap(cap),cost(cost),rev(rev) {}
};
vector<edge> G[MAX_V];
double dist[MAX_V];
int prevv[MAX_V],preve[MAX_V];
void add_edge(int from,int to,int cap,double cost){
  G[from].push_back(edge(to,cap,cost,G[to].size()));
  G[to].push_back(edge(from,0,-cost,G[from].size()-1));
}
double min_cost_flow(int s,int t,int f){
  double res=0;
  while(f>0){
    fill(dist,dist+MAX_V,INF);dist[s]=0;
    bool update=true;
    while(update){
      update=false;
      for(int v=0;v<MAX_V;v++){
        if(dist[v]==INF) continue;
        for(int i=0;i<(int)G[v].size();i++){
          edge &e=G[v][i];
          if(e.cap>0 && dist[e.to]>dist[v]+e.cost+EPS){
            dist[e.to]=dist[v]+e.cost;
            prevv[e.to]=v; preve[e.to]=i; update=true;
          }
        }
      }
    }
    if(dist[t]==INF)return -1;
    int d=f;
    for(int v=t;v!=s;v=prevv[v]){
      d=min(d,G[prevv[v]][preve[v]].cap);
    }
    f-=d;res+=dist[t]*d;
    for(int v=t;v!=s;v=prevv[v]){
      edge &e=G[prevv[v]][preve[v]];
      e.cap-=d;G[v][e.rev].cap+=d;
    }
  }
  return res;
}

int main() {
  int n;
  cin >> n;
  C c[2];
  for(int i=0,x,y,z; i<2; i++) {
    cin >> x >> y >> z;
    c[i]=(C){P(x,y),z};
  }
  P a[n],b[n];
  vector<L> v[n],v2[n];
  for(int i=0,x,y; i<n; i++) {
    cin >> x >> y;
    a[i]=P(x,y);
    for(int j=0; j<2; j++) {
      vector<P> g=tangent(c[j],a[i]);
      for(int k=0; k<g.size(); k++) v[i].push_back(L(a[i],g[k]));
    }
  }
  for(int i=0,x,y; i<n; i++) {
    cin >> x >> y;
    b[i]=P(x,y);
    for(int j=0; j<2; j++) {
      vector<P> g=tangent(c[j],b[i]);
      for(int k=0; k<g.size(); k++) v2[i].push_back(L(b[i],g[k]));
    }
  }
  double d[n][n];
  for(int i=0; i<n; i++) {
    for(int j=0; j<n; j++) {
      d[i][j]=INF;
      for(int k=0; k<v[i].size(); k++) {
        for(int l=0; l<v2[j].size(); l++) {
          if(!intersectLL(v[i][k],v2[j][l])) continue;
          P p=crosspoint(v[i][k],v2[j][l]);
          bool f=1;
          for(int x=0; x<2; x++) {
            if(D(p,c[x].p)<c[x].r) f=0;
            if(getIntersectCS(c[x],L(a[i],p)).size()>=2) f=0;
            if(getIntersectCS(c[x],L(b[j],p)).size()>=2) f=0;
          }
          if(f) d[i][j]=min(d[i][j],D(a[i],p)+D(b[j],p));
        }
      }
      bool f=1;
      for(int x=0; x<2; x++) {
        if(getIntersectCS(c[x],L(a[i],b[j])).size()>=2) f=0;
      }
      if(f) d[i][j]=min(d[i][j],D(a[i],b[j]));
      if(d[i][j]!=INF) add_edge(i,n+j,1,d[i][j]);
    }
    add_edge(1000,i,1,0);
    add_edge(i+n,1001,1,0);
  }
  double ans=min_cost_flow(1000,1001,n);
  if(ans<0) printf("Impossible\n");
  else printf("%.10f\n",ans);
  return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 4428
final_rank: 5

code_snippet: #include <iostream>
#include <vector>
#include <array>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <tuple>
#include <bitset>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>

constexpr double EPS = 0.000000001;
struct Coordinate;
struct Vector;
struct Segment;
struct Angle;
struct Line;
struct Circle;
struct Coordinate {
	double x, y;
	double distance(const Coordinate& that) const;
	Vector operator-(const Coordinate& from) const;
};
struct Vector {
	double x, y;
	Vector rotate(const Angle& angle) const;
	double dot(const Vector& that) const;
	double cross(const Vector& that) const;
	double length() const;
};
Vector operator*(const double& scala, const Vector& vec);
Vector operator*(const Vector& vec, const double scala);
Coordinate operator+(const Coordinate& coord, const Vector& diff);
Coordinate operator+(const Vector& diff, const Coordinate& coord);
struct Segment {
	Coordinate end_a, end_b;
	bool has_intersection(const Circle& that) const;
	double distance(const Coordinate& that) const;
};
struct Angle {
	double sin, cos;
	static Angle from_sin(const double sin);
	Angle operator+(const Angle& that) const;
	Angle operator-() const;
};
struct Line {
private:
	const Coordinate from, to;
	Vector vec() const { return to - from; }
	double a() const { return to.y - from.y; }
	double b() const { return from.x - to.x; }
	double c() const { return - a() * from.x - from.y * b(); }
public:
	Line(const Coordinate& a, const Coordinate& b) : to{ a }, from{ b } {};
	bool is_cross(const Line& that) const;
	Coordinate cross_point(const Line& that) const;
};
struct Circle {
	Coordinate center;
	double radius;
	std::vector<Line> tangents(const Coordinate& that) const;
};

double Coordinate::distance(const Coordinate& that) const
{
	return (*this - that).length();
}

Vector Coordinate::operator-(const Coordinate& from) const
{
	return Vector{ x - from.x, y - from.y };
}

Vector Vector::rotate(const Angle& angle) const
{
	auto len = length();
	auto a = Angle{ y / len, x / len } + angle;
	return Vector{ a.cos * len, a.sin* len };
}

double Vector::dot(const Vector& that) const
{
	return x * that.x + y * that.y;
}

double Vector::cross(const Vector& that) const
{
	return x * that.y - y * that.x;
}

double Vector::length() const
{
	return std::sqrt(x * x + y * y);
}

Vector operator*(const double& scala, const Vector& vec)
{
	return Vector{ vec.x * scala, vec.y * scala };
}

Vector operator*(const Vector& vec, const double scala)
{
	return Vector{ vec.x * scala, vec.y * scala };
}

Coordinate operator+(const Coordinate& coord, const Vector& diff)
{
	return Coordinate{ coord.x + diff.x, coord.y + diff.y };
}

Coordinate operator+(const Vector& diff, const Coordinate& coord)
{
	return Coordinate{ diff.x + coord.x, diff.y + coord.y };
}

std::vector<Line> Circle::tangents(const Coordinate& that) const
{
	const auto mid = center - that;
	const auto angle = Angle::from_sin(radius / center.distance(that));
	return { Line(that, mid.rotate(angle) + that), Line(that, mid.rotate(-angle) + that) };
}

bool Line::is_cross(const Line& that) const
{
	return std::abs(vec().cross(that.vec())) > 0;
}

Coordinate Line::cross_point(const Line& that) const
{
	const auto d = a() * that.b() - that.a() * b();
	return Coordinate{ (b() * that.c() - that.b() * c()) / d, (that.a() * c() - a() * that.c()) / d };
}

Angle Angle::from_sin(const double sin)
{
	return Angle{ sin, std::sqrt(1 - sin * sin) };
}

Angle Angle::operator+(const Angle& that) const
{
	return Angle{ sin * that.cos + cos * that.sin, cos * that.cos - sin * that.sin };
}

Angle Angle::operator-() const
{
	return Angle{ -sin, cos };
}

bool Segment::has_intersection(const Circle& that) const
{
	return distance(that.center) < that.radius - EPS;
}

double Segment::distance(const Coordinate& that) const
{
	const auto vec = end_a - end_b;
	if (vec.dot(that - end_b) >= 0 && vec.dot(end_a - that) >= 0) {
		return std::abs(vec.y * that.x - vec.x * that.y + end_a.x * end_b.y - end_a.y * end_b.x) / std::sqrt(vec.y * vec.y + vec.x * vec.x);
	}
	else {
		return std::min(end_a.distance(that), end_b.distance(that));
	}
}

struct Edge {
	int to;
	double cost;
	Edge* pair{ nullptr };
	bool has_flow;
	Edge(int _to, double _cost, bool _has_flow) :to{ _to }, cost{ _cost }, has_flow{ _has_flow }{};
};
template<typename K, typename V>
struct KeyWithValue {
	K key;
	V value;
	KeyWithValue(const K& k, const V& v) :key{ k }, value{ v }{};
};
template<typename K, typename V>
bool operator>(const KeyWithValue<K, V>& a, const KeyWithValue<K, V>& b) {
	return a.key > b.key;
}
void set_edge(std::vector<std::vector<Edge>>& node, const int from, const int to, double cost) {
	node[from].emplace_back(to, cost, true);
	node[to].emplace_back(from, -cost, false);
	node[from].back().pair = &node[to].back();
	node[to].back().pair = &node[from].back();
}
double min_cost_matching(std::vector<std::vector<Edge>> &nodes, const int flow, const int source, const int sink) {
	std::vector<double> min_cost(nodes.size());
	std::vector<double> potential(nodes.size(), 0);
	std::vector<Edge*> prev(nodes.size(), nullptr);
	std::priority_queue<KeyWithValue<double, int>, std::vector<KeyWithValue<double, int>>, std::greater<KeyWithValue<double, int>>> queue;
	double result = 0;
	for (auto _i = 0; _i < flow; ++_i) {
		std::fill(min_cost.begin(), min_cost.end(), DBL_MAX);
		min_cost[source] = 0;
		queue.emplace(0.0, source);
		while (!queue.empty()) {
			auto top = queue.top(); queue.pop();
			if (top.key == min_cost[top.value]) {
				for (auto& edge : nodes[top.value]) if (edge.has_flow) {
					if (min_cost[edge.to] > potential[top.value] + edge.cost - potential[edge.to] + top.key + EPS) {
						min_cost[edge.to] = potential[top.value] + edge.cost - potential[edge.to] + top.key;
						prev[edge.to] = &edge;
						queue.emplace(min_cost[edge.to], edge.to);
					}
				}
			}
		}
		if (min_cost[sink] == DBL_MAX) return -1;
		for (auto i = 0; i < nodes.size(); ++i) potential[i] += min_cost[i];
		result += potential[sink];
		auto last = sink;
		while (last != source) {
			auto prev_edge = prev[last];
			prev_edge->has_flow = false;
			prev_edge->pair->has_flow = true;
			last = prev_edge->pair->to;
		}
	}
	return result;
}
double cal_min_cost(const std::vector<Coordinate>& red, const std::vector<Coordinate>& blue, const std::vector<Circle>& circles) {
	std::vector<std::vector<std::vector<Line>>> red_tangents(red.size()), blue_tangents(blue.size());
	for (auto i = 0; i < red.size(); ++i) {
		for (const auto &circle: circles) {
			red_tangents[i].push_back(circle.tangents(red[i]));
			blue_tangents[i].push_back(circle.tangents(blue[i]));
		}
	}
	const int source = red.size() + blue.size();
	const int sink = source + 1;
	std::vector<std::vector<Edge>> node(sink + 1); for (auto& n : node) n.reserve(red.size() + 1);
	for (auto r = 0; r < red.size(); ++r) for (auto b = 0; b < blue.size(); ++b){
		const auto red_pos = red[r];
		const auto blue_pos = blue[b];
		double min_cost = DBL_MAX;
		const auto direct = Segment{ red_pos, blue_pos };
		bool is_blocked = false;
		for (const auto& c : circles) if (!is_blocked) {
			is_blocked = direct.has_intersection(c);
		}
		if (is_blocked) {
			for (auto i = 0; i < circles.size(); ++i) for (auto j = 0; j < circles.size(); ++j) {
				for (const auto& red_tangent : red_tangents[r][i]) for (const auto& blue_tangent : blue_tangents[b][j]) if (red_tangent.is_cross(blue_tangent)) {
					const auto cross_point = red_tangent.cross_point(blue_tangent);
					const auto red_to_cp = Segment{ cross_point, red_pos };
					const auto blue_to_cp = Segment{ cross_point, blue_pos };
					bool is_blocked = false;
					for (auto c = 0; c < circles.size() && !is_blocked; ++c) {
						/*
						if (i == c && red_to_cp.has_intersection(circles[c])) {
							std::cerr << "i: " << i << '\n';
						}
						if (j == c && blue_to_cp.has_intersection(circles[c])) {
							std::cerr << "i: " << i << '\n';
						}
						*/
						is_blocked = ((i != c) && red_to_cp.has_intersection(circles[c])) || ((j != c) && blue_to_cp.has_intersection(circles[c]));
					}
					if (!is_blocked) {
						min_cost = std::min(min_cost, red_pos.distance(cross_point) + blue_pos.distance(cross_point));
					}
				}
			}
		}
		else {
			min_cost = red_pos.distance(blue_pos);
		}
		if (min_cost <= 10000) {
			set_edge(node, r, b + red.size(), min_cost);
		}
	}
	for (auto r = 0; r < red.size(); ++r) {
		set_edge(node, source, r, 0);
	}
	for (auto b = 0; b < blue.size(); ++b) {
		set_edge(node, b + red.size(), sink, 0);
	}
	return min_cost_matching(node, red.size(), source, sink);
}
int main() {
	int n; std::cin >> n;
	std::vector<Circle> circles(2); for (auto& c : circles) std::cin >> c.center.x >> c.center.y >> c.radius;
	std::vector<Coordinate> red(n), blue(n); 
	for (auto& r : red) std::cin >> r.x >> r.y;
	for (auto& b : blue) std::cin >> b.x >> b.y;
	auto min_cost = cal_min_cost(red, blue, circles);
	if (min_cost >= 0) {
		std::cout << std::setprecision(10) << std::fixed << min_cost << '\n';
	}
	else {
		std::cout << "Impossible\n";
	}
	return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 3852
final_rank: 1

code_snippet: #include <iostream>
#include <vector>
#include <array>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <tuple>
#include <bitset>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>

constexpr double EPS = 0.000000001;
constexpr double DBL_MAX_VALUE = 1e9;
struct Coordinate;
struct Vector;
struct Segment;
struct Angle;
struct Line;
struct Circle;
struct Coordinate {
	double x, y;
	double distance(const Coordinate& that) const;
	Vector operator-(const Coordinate& from) const;
};
struct Vector {
	double x, y;
	Vector rotate(const Angle& angle) const;
	double dot(const Vector& that) const;
	double cross(const Vector& that) const;
	double length() const;
};
Vector operator*(const double& scala, const Vector& vec);
Vector operator*(const Vector& vec, const double scala);
Coordinate operator+(const Coordinate& coord, const Vector& diff);
Coordinate operator+(const Vector& diff, const Coordinate& coord);
struct Segment {
	Coordinate end_a, end_b;
	bool has_intersection(const Circle& that) const;
	double distance(const Coordinate& that) const;
};
struct Angle {
	double sin, cos;
	static Angle from_sin(const double sin);
	Angle operator+(const Angle& that) const;
	Angle operator-() const;
};
struct Line {
private:
	const Coordinate from, to;
	Vector vec() const { return to - from; }
	double a() const { return to.y - from.y; }
	double b() const { return from.x - to.x; }
	double c() const { return - a() * from.x - from.y * b(); }
public:
	Line(const Coordinate& a, const Coordinate& b) : to{ a }, from{ b } {};
	bool is_cross(const Line& that) const;
	Coordinate cross_point(const Line& that) const;
};
struct Circle {
	Coordinate center;
	double radius;
	std::vector<Line> tangents(const Coordinate& that) const;
};

double Coordinate::distance(const Coordinate& that) const
{
	return (*this - that).length();
}

Vector Coordinate::operator-(const Coordinate& from) const
{
	return Vector{ x - from.x, y - from.y };
}

Vector Vector::rotate(const Angle& angle) const
{
	auto len = length();
	auto a = Angle{ y / len, x / len } + angle;
	return Vector{ a.cos * len, a.sin* len };
}

double Vector::dot(const Vector& that) const
{
	return x * that.x + y * that.y;
}

double Vector::cross(const Vector& that) const
{
	return x * that.y - y * that.x;
}

double Vector::length() const
{
	return std::sqrt(x * x + y * y);
}

Vector operator*(const double& scala, const Vector& vec)
{
	return Vector{ vec.x * scala, vec.y * scala };
}

Vector operator*(const Vector& vec, const double scala)
{
	return Vector{ vec.x * scala, vec.y * scala };
}

Coordinate operator+(const Coordinate& coord, const Vector& diff)
{
	return Coordinate{ coord.x + diff.x, coord.y + diff.y };
}

Coordinate operator+(const Vector& diff, const Coordinate& coord)
{
	return Coordinate{ diff.x + coord.x, diff.y + coord.y };
}

std::vector<Line> Circle::tangents(const Coordinate& that) const
{
	const auto mid = center - that;
	const auto angle = Angle::from_sin(radius / center.distance(that));
	return { Line(that, mid.rotate(angle) + that), Line(that, mid.rotate(-angle) + that) };
}

bool Line::is_cross(const Line& that) const
{
	return std::abs(vec().cross(that.vec())) > 0;
}

Coordinate Line::cross_point(const Line& that) const
{
	const auto d = a() * that.b() - that.a() * b();
	return Coordinate{ (b() * that.c() - that.b() * c()) / d, (that.a() * c() - a() * that.c()) / d };
}

Angle Angle::from_sin(const double sin)
{
	return Angle{ sin, std::sqrt(1 - sin * sin) };
}

Angle Angle::operator+(const Angle& that) const
{
	return Angle{ sin * that.cos + cos * that.sin, cos * that.cos - sin * that.sin };
}

Angle Angle::operator-() const
{
	return Angle{ -sin, cos };
}

bool Segment::has_intersection(const Circle& that) const
{
	return distance(that.center) < that.radius - EPS;
}

double Segment::distance(const Coordinate& that) const
{
	const auto vec = end_a - end_b;
	if (vec.dot(that - end_b) >= 0 && vec.dot(end_a - that) >= 0) {
		return std::abs(vec.y * that.x - vec.x * that.y + end_a.x * end_b.y - end_a.y * end_b.x) / std::sqrt(vec.y * vec.y + vec.x * vec.x);
	}
	else {
		return std::min(end_a.distance(that), end_b.distance(that));
	}
}

struct Edge {
	int to;
	double cost;
	Edge* pair{ nullptr };
	bool has_flow;
	Edge(int _to, double _cost, bool _has_flow) :to{ _to }, cost{ _cost }, has_flow{ _has_flow }{};
};
template<typename K, typename V>
struct KeyWithValue {
	K key;
	V value;
	KeyWithValue(const K& k, const V& v) :key{ k }, value{ v }{};
};
template<typename K, typename V>
bool operator>(const KeyWithValue<K, V>& a, const KeyWithValue<K, V>& b) {
	return a.key > b.key;
}
void set_edge(std::vector<std::vector<Edge>>& node, const int from, const int to, double cost) {
	node[from].emplace_back(to, cost, true);
	node[to].emplace_back(from, -cost, false);
	node[from].back().pair = &node[to].back();
	node[to].back().pair = &node[from].back();
}
double min_cost_matching(std::vector<std::vector<Edge>> &nodes, const int flow, const int source, const int sink) {
	std::vector<double> min_cost(nodes.size());
	std::vector<double> potential(nodes.size(), 0);
	std::vector<Edge*> prev(nodes.size(), nullptr);
	std::priority_queue<KeyWithValue<double, int>, std::vector<KeyWithValue<double, int>>, std::greater<KeyWithValue<double, int>>> queue;
	double result = 0;
	for (auto _i = 0; _i < flow; ++_i) {
		std::fill(min_cost.begin(), min_cost.end(), DBL_MAX_VALUE);
		min_cost[source] = 0;
		queue.emplace(0.0, source);
		while (!queue.empty()) {
			auto top = queue.top(); queue.pop();
			if (top.key == min_cost[top.value]) {
				for (auto& edge : nodes[top.value]) if (edge.has_flow) {
					if (min_cost[edge.to] > potential[top.value] + edge.cost - potential[edge.to] + top.key + EPS) {
						min_cost[edge.to] = potential[top.value] + edge.cost - potential[edge.to] + top.key;
						prev[edge.to] = &edge;
						queue.emplace(min_cost[edge.to], edge.to);
					}
				}
			}
		}
		if (min_cost[sink] == DBL_MAX_VALUE) return -1;
		for (auto i = 0; i < nodes.size(); ++i) potential[i] += min_cost[i];
		result += potential[sink];
		auto last = sink;
		while (last != source) {
			auto prev_edge = prev[last];
			prev_edge->has_flow = false;
			prev_edge->pair->has_flow = true;
			last = prev_edge->pair->to;
		}
	}
	return result;
}
double cal_min_cost(const std::vector<Coordinate>& red, const std::vector<Coordinate>& blue, const std::vector<Circle>& circles) {
	std::vector<std::vector<std::vector<Line>>> red_tangents(red.size()), blue_tangents(blue.size());
	for (auto i = 0; i < red.size(); ++i) {
		for (const auto &circle: circles) {
			red_tangents[i].push_back(circle.tangents(red[i]));
			blue_tangents[i].push_back(circle.tangents(blue[i]));
		}
	}
	const int source = red.size() + blue.size();
	const int sink = source + 1;
	std::vector<std::vector<Edge>> node(sink + 1); for (auto& n : node) n.reserve(red.size() + 1);
	for (auto r = 0; r < red.size(); ++r) for (auto b = 0; b < blue.size(); ++b){
		const auto red_pos = red[r];
		const auto blue_pos = blue[b];
		double min_cost = DBL_MAX;
		const auto direct = Segment{ red_pos, blue_pos };
		bool is_blocked = false;
		for (const auto& c : circles) if (!is_blocked) {
			is_blocked = direct.has_intersection(c);
		}
		if (is_blocked) {
			for (auto i = 0; i < circles.size(); ++i) for (auto j = 0; j < circles.size(); ++j) {
				for (const auto& red_tangent : red_tangents[r][i]) for (const auto& blue_tangent : blue_tangents[b][j]) if (red_tangent.is_cross(blue_tangent)) {
					const auto cross_point = red_tangent.cross_point(blue_tangent);
					const auto red_to_cp = Segment{ cross_point, red_pos };
					const auto blue_to_cp = Segment{ cross_point, blue_pos };
					bool is_blocked = false;
					for (auto c = 0; c < circles.size() && !is_blocked; ++c) {
						if (i == c && red_to_cp.has_intersection(circles[c])) {
							std::cerr << "i: " << i << '\n';
						}
						if (j == c && blue_to_cp.has_intersection(circles[c])) {
							std::cerr << "i: " << i << '\n';
						}
						is_blocked = ((i != c) && red_to_cp.has_intersection(circles[c])) || ((j != c) && blue_to_cp.has_intersection(circles[c]));
					}
					if (!is_blocked) {
						min_cost = std::min(min_cost, red_pos.distance(cross_point) + blue_pos.distance(cross_point));
					}
				}
			}
		}
		else {
			min_cost = red_pos.distance(blue_pos);
		}
		if (min_cost <= 10000) {
			set_edge(node, r, b + red.size(), min_cost);
		}
	}
	for (auto r = 0; r < red.size(); ++r) {
		set_edge(node, source, r, 0);
	}
	for (auto b = 0; b < blue.size(); ++b) {
		set_edge(node, b + red.size(), sink, 0);
	}
	return min_cost_matching(node, red.size(), source, sink);
}
int main() {
	int n; std::cin >> n;
	std::vector<Circle> circles(2); for (auto& c : circles) std::cin >> c.center.x >> c.center.y >> c.radius;
	std::vector<Coordinate> red(n), blue(n); 
	for (auto& r : red) std::cin >> r.x >> r.y;
	for (auto& b : blue) std::cin >> b.x >> b.y;
	auto min_cost = cal_min_cost(red, blue, circles);
	if (min_cost >= 0) {
		std::cout << std::setprecision(10) << std::fixed << min_cost << '\n';
	}
	else {
		std::cout << "Impossible\n";
	}
	return 0;
}
accuracy: 0.59375
time_ms: 10
memory_kb: 3748
final_rank: 9

code_snippet: #include "bits/stdc++.h"

using namespace std;

using ld = double;
using Point = std::complex<ld>;

const ld eps = 1e-9, pi = acos(-1.0);

namespace std
{
bool operator<(const Point &lhs, const Point &rhs)
{
    if (lhs.real() < rhs.real() - eps)
        return true;
    if (lhs.real() > rhs.real() + eps)
        return false;
    return lhs.imag() < rhs.imag();
}
} // namespace std

Point input_point()
{
    ld x, y;
    std::cin >> x >> y;
    return Point(x, y);
}

bool eq(ld a, ld b)
{
    return (abs(a - b) < eps);
}

ld dot(Point a, Point b)
{
    return real(conj(a) * b);
}

ld cross(Point a, Point b)
{
    return imag(conj(a) * b);
}

// CCW::counter clockwise
int ccw(Point a, Point b, Point c)
{
    b -= a;
    c -= a;
    if (cross(b, c) > eps)
        return 1; // a,b,c : counter-clockwise
    if (cross(b, c) < -eps)
        return -1; // a,b,c : clockwise
    if (dot(b, c) < 0)
        return 2; // c,a,b : on a line
    if (norm(b) < norm(c))
        return -2; // a,b,c : on a line
    return 0;      // a,c,b : on a line
}

class Line
{
public:
    Point a, b;
    Line() : a(Point(0, 0)), b(Point(0, 0)) {}
    Line(Point a, Point b) : a(a), b(b) {}
};

ld dot(Line l, Line m)
{
    return dot((l.a - l.b), (m.a - m.b));
}

// l:line, m:line が交点を持つか
bool isis_ll(Line l, Line m)
{
    return !eq(cross(l.b - l.a, m.b - m.a), 0);
}

// l:line, s:segment
bool isis_ls(Line l, Line s)
{
    return isis_ll(l, s) &&
           (cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}

// s:segment, t:segment
bool isis_ss(Line s, Line t)
{
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
           ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

// p が l:line 上に存在するか
bool isis_lp(Line l, Point p)
{
    return (abs(cross(l.b - p, l.a - p)) < eps);
}

bool isis_sp(Line s, Point p)
{
    return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}

// p から l に下ろした足との交点
Point proj(Line l, Point p)
{
    ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + t * (l.a - l.b);
}

// l:line, t:line の交点
Point is_ll(Line l, Line m)
{
    Point lv = l.b - l.a, mv = m.b - m.a;
    assert(cross(lv, mv) != 0);
    return l.a + lv * cross(mv, m.a - l.a) / cross(mv, lv);
}

// p, l:line の距離
ld dist_lp(Line l, Point p)
{
    return abs(p - proj(l, p));
}

ld dist_ll(Line l, Line m)
{
    return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}

ld dist_ls(Line l, Line s)
{
    return isis_ls(l, s) ? 0 : std::min(dist_lp(l, s.a), dist_lp(l, s.b));
}

ld dist_sp(Line s, Point p)
{
    Point r = proj(s, p);
    return isis_sp(s, r) ? abs(r - p) : std::min(abs(s.a - p), abs(s.b - p));
}

ld dist_ss(Line s, Line t)
{
    if (isis_ss(s, t))
        return 0;
    return std::min({dist_sp(s, t.a), dist_sp(s, t.b), dist_sp(t, s.a), dist_sp(t, s.b)});
}

class Circle
{
public:
    Point p;
    ld r;
    Circle() : p(Point(0, 0)), r(0) {}
    Circle(Point p, ld r) : p(p), r(r) {}
};

// c1, c2 の交点
std::vector<Point> is_cc(Circle c1, Circle c2)
{
    std::vector<Point> res;
    ld d = abs(c1.p - c2.p);
    ld rc = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
    ld dfr = c1.r * c1.r - rc * rc;
    if (abs(dfr) < eps)
        dfr = 0.0;
    else if (dfr < 0.0)
        return res; // no intersection
    ld rs = sqrt(dfr);
    Point diff = (c2.p - c1.p) / d;
    res.emplace_back(c1.p + diff * Point(rc, rs));
    if (dfr != 0.0)
        res.emplace_back(c1.p + diff * Point(rc, -rs));
    return res;
}

std::vector<Point> is_lc(Circle c, Line l)
{
    std::vector<Point> res;
    ld d = dist_lp(l, c.p);
    if (d < c.r + eps)
    {
        ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d); //safety;
        Point nor = (l.a - l.b) / abs(l.a - l.b);
        res.emplace_back(proj(l, c.p) + len * nor);
        res.emplace_back(proj(l, c.p) - len * nor);
    }
    return res;
}

std::vector<Point> is_sc(Circle c, Line l)
{
    std::vector<Point> v = is_lc(c, l), res;
    for (Point p : v)
        if (isis_sp(l, p))
            res.emplace_back(p);
    return res;
}

// p から c への接線
std::vector<Line> tangent_cp(Circle c, Point p)
{
    std::vector<Line> ret;
    Point v = c.p - p;
    ld d = abs(v);
    ld l = sqrt(norm(v) - c.r * c.r);
    if (isnan((long double)l))
    {
        return ret;
    }
    Point v1 = v * Point(l / d, c.r / d);
    Point v2 = v * Point(l / d, -c.r / d);
    ret.emplace_back(Line(p, p + v1));
    if (l < eps)
        return ret;
    ret.emplace_back(Line(p, p + v2));
    return ret;
}

bool isContain(Circle c, Line l)
{
    return dist_sp(l, c.p) + eps < c.r;
}

class minCostFlow
{
    using capacity_type = int;
    using cost_type = double;
    using pii = std::pair<cost_type, int>;
    const int INF = 1e9;
    struct Edge
    {
        int to, rev;
        capacity_type cap;
        cost_type cost;
        Edge(int to_, int _rev, capacity_type cap_, cost_type cost_)
            : to(to_), rev(_rev), cap(cap_), cost(cost_) {}
    };
    int V;
    std::vector<std::vector<Edge>> G;
    // ポテンシャル
    std::vector<cost_type> h;
    // 最短距離
    std::vector<cost_type> dist;
    // 直前の頂点, 辺
    std::vector<int> prevv, preve;

public:
    minCostFlow(int _V) : V(_V), G(_V), h(_V), dist(_V), prevv(_V), preve(_V) {}
    void add(int from, int to, capacity_type cap, cost_type cost)
    {
        G[from].push_back(Edge(to, G[to].size(), cap, cost));
        G[to].push_back(Edge(from, G[from].size() - 1, 0, -cost));
    }
    cost_type calc(int s, int t, int f)
    {
        cost_type res = 0;
        fill(h.begin(), h.end(), 0);
        while (f > 0)
        {
            std::priority_queue<pii, std::vector<pii>, std::greater<pii>> que;
            fill(dist.begin(), dist.end(), INF);
            dist[s] = 0;
            que.push(pii(0, s));
            while (!que.empty())
            {
                pii p = que.top();
                que.pop();
                int v = p.second;
                if (dist[v] < p.first)
                    continue;
                for (size_t i = 0; i < G[v].size(); i++)
                {
                    Edge &e = G[v][i];
                    if (e.cap > eps && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to] + eps)
                    {
                        dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
                        prevv[e.to] = v;
                        preve[e.to] = i;
                        que.push(pii(dist[e.to], e.to));
                    }
                }
            }
            if (dist[t] == INF)
                return -1;
            for (int v = 0; v < V; v++)
                h[v] += dist[v];
            capacity_type d = f;
            for (int v = t; v != s; v = prevv[v])
            {
                d = std::min(d, G[prevv[v]][preve[v]].cap);
            }
            f -= d;
            res += d * h[t];
            for (int v = t; v != s; v = prevv[v])
            {
                Edge &e = G[prevv[v]][preve[v]];
                e.cap -= d;
                G[v][e.rev].cap += d;
            }
        }
        return res;
    }
};

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    int n;
    cin >> n;
    ld x1, y1, r1, x2, y2, r2;
    cin >> x1 >> y1 >> r1 >> x2 >> y2 >> r2;
    Circle c1(Point(x1, y1), r1), c2(Point(x2, y2), r2);
    vector<Point> rs, bs;
    for (int i = 0; i < n; i++)
    {
        rs.push_back(input_point());
    }
    for (int i = 0; i < n; i++)
    {
        bs.push_back(input_point());
    }
    // dist[i][j] := rs[i], bs[j] の最短移動距離
    vector<vector<ld>> dist(n, vector<ld>(n, 1e15));
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            Line l = Line(rs[i], bs[j]);
            if (is_sc(c1, l).size() <= 1 && is_sc(c2, l).size() <= 1)
            {
                dist[i][j] = abs(rs[i] - bs[j]);
                continue;
            }
            // rs[i] から c1 への接線
            auto rl1 = tangent_cp(c1, rs[i]);
            // bs[j] から c1 への接線
            auto bl1 = tangent_cp(c1, bs[j]);
            // rs[i], c2 への接線
            auto rl2 = tangent_cp(c2, rs[i]);
            // bs[j], c2 への接線
            auto bl2 = tangent_cp(c2, bs[j]);
            for (auto l1 : rl1)
            {
                for (auto l2 : bl1)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c2, Line(rs[i], p)) || isContain(c2, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
            for (auto l1 : rl2)
            {
                for (auto l2 : bl2)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c1, Line(rs[i], p)) || isContain(c1, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
            // rs[i]-c1, bs[j]-c2
            for (auto l1 : rl1)
            {
                for (auto l2 : bl2)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c2, Line(rs[i], p)) || isContain(c1, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
            // rs[i]-c2, bs[j]-c1
            for (auto l1 : rl2)
            {
                for (auto l2 : bl1)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c1, Line(rs[i], p)) || isContain(c2, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
        }
    }
    minCostFlow mcf(2 * n + 2);
    for (int i = 0; i < n; i++)
    {
        mcf.add(0, i + 1, 1, 0);
        mcf.add(n + i + 1, 2 * n + 1, 1, 0);
        for (int j = 0; j < n; j++)
        {
            int st = i + 1, gt = n + 1 + j;
            if (dist[i][j] != 1e15)
            {
                mcf.add(st, gt, 1, dist[i][j]);
            }
        }
    }
    auto ret = mcf.calc(0, 2 * n + 1, n);
    if (ret == -1)
        cout << "Impossible" << endl;
    else
        cout << fixed << setprecision(10) << ret << endl;
}
accuracy: 1
time_ms: 30
memory_kb: 4016
final_rank: 2

code_snippet: #include "bits/stdc++.h"

using namespace std;

using ld = double;
using Point = std::complex<ld>;

const ld eps = 1e-9, pi = acos(-1.0);

namespace std
{
bool operator<(const Point &lhs, const Point &rhs)
{
    if (lhs.real() < rhs.real() - eps)
        return true;
    if (lhs.real() > rhs.real() + eps)
        return false;
    return lhs.imag() < rhs.imag();
}
} // namespace std

Point input_point()
{
    ld x, y;
    std::cin >> x >> y;
    return Point(x, y);
}

bool eq(ld a, ld b)
{
    return (abs(a - b) < eps);
}

ld dot(Point a, Point b)
{
    return real(conj(a) * b);
}

ld cross(Point a, Point b)
{
    return imag(conj(a) * b);
}

// CCW::counter clockwise
int ccw(Point a, Point b, Point c)
{
    b -= a;
    c -= a;
    if (cross(b, c) > eps)
        return 1; // a,b,c : counter-clockwise
    if (cross(b, c) < -eps)
        return -1; // a,b,c : clockwise
    if (dot(b, c) < 0)
        return 2; // c,a,b : on a line
    if (norm(b) < norm(c))
        return -2; // a,b,c : on a line
    return 0;      // a,c,b : on a line
}

class Line
{
public:
    Point a, b;
    Line() : a(Point(0, 0)), b(Point(0, 0)) {}
    Line(Point a, Point b) : a(a), b(b) {}
};

bool isis_sp(Line s, Point p)
{
    return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}

// p から l に下ろした足との交点
Point proj(Line l, Point p)
{
    ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + t * (l.a - l.b);
}

// l:line, t:line の交点
Point is_ll(Line l, Line m)
{
    Point lv = l.b - l.a, mv = m.b - m.a;
    assert(cross(lv, mv) != 0);
    return l.a + lv * cross(mv, m.a - l.a) / cross(mv, lv);
}

// p, l:line の距離
ld dist_lp(Line l, Point p)
{
    return abs(p - proj(l, p));
}

ld dist_sp(Line s, Point p)
{
    Point r = proj(s, p);
    return isis_sp(s, r) ? abs(r - p) : std::min(abs(s.a - p), abs(s.b - p));
}

class Circle
{
public:
    Point p;
    ld r;
    Circle() : p(Point(0, 0)), r(0) {}
    Circle(Point p, ld r) : p(p), r(r) {}
};

std::vector<Point> is_lc(Circle c, Line l)
{
    std::vector<Point> res;
    ld d = dist_lp(l, c.p);
    if (d < c.r + eps)
    {
        ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d); //safety;
        Point nor = (l.a - l.b) / abs(l.a - l.b);
        res.emplace_back(proj(l, c.p) + len * nor);
        res.emplace_back(proj(l, c.p) - len * nor);
    }
    return res;
}

std::vector<Point> is_sc(Circle c, Line l)
{
    std::vector<Point> v = is_lc(c, l), res;
    for (Point p : v)
        if (isis_sp(l, p))
            res.emplace_back(p);
    return res;
}

// p から c への接線
std::vector<Line> tangent_cp(Circle c, Point p)
{
    std::vector<Line> ret;
    Point v = c.p - p;
    ld d = abs(v);
    ld l = sqrt(norm(v) - c.r * c.r);
    if (isnan((long double)l))
    {
        return ret;
    }
    Point v1 = v * Point(l / d, c.r / d);
    Point v2 = v * Point(l / d, -c.r / d);
    ret.emplace_back(Line(p, p + v1));
    if (l < eps)
        return ret;
    ret.emplace_back(Line(p, p + v2));
    return ret;
}

bool isContain(Circle c, Line l)
{
    return dist_sp(l, c.p) + eps < c.r;
}

class minCostFlow
{
    using capacity_type = int;
    using cost_type = double;
    using pii = std::pair<cost_type, int>;
    const int INF = 1e9;
    struct Edge
    {
        int to, rev;
        capacity_type cap;
        cost_type cost;
        Edge(int to_, int _rev, capacity_type cap_, cost_type cost_)
            : to(to_), rev(_rev), cap(cap_), cost(cost_) {}
    };
    int V;
    std::vector<std::vector<Edge>> G;
    // ポテンシャル
    std::vector<cost_type> h;
    // 最短距離
    std::vector<cost_type> dist;
    // 直前の頂点, 辺
    std::vector<int> prevv, preve;

public:
    minCostFlow(int _V) : V(_V), G(_V), h(_V), dist(_V), prevv(_V), preve(_V) {}
    void add(int from, int to, capacity_type cap, cost_type cost)
    {
        G[from].push_back(Edge(to, G[to].size(), cap, cost));
        G[to].push_back(Edge(from, G[from].size() - 1, 0, -cost));
    }
    cost_type calc(int s, int t, int f)
    {
        cost_type res = 0;
        fill(h.begin(), h.end(), 0);
        while (f > 0)
        {
            std::priority_queue<pii, std::vector<pii>, std::greater<pii>> que;
            fill(dist.begin(), dist.end(), INF);
            dist[s] = 0;
            que.push(pii(0, s));
            while (!que.empty())
            {
                pii p = que.top();
                que.pop();
                int v = p.second;
                if (dist[v] < p.first)
                    continue;
                for (size_t i = 0; i < G[v].size(); i++)
                {
                    Edge &e = G[v][i];
                    if (e.cap > eps && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to] + eps)
                    {
                        dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
                        prevv[e.to] = v;
                        preve[e.to] = i;
                        que.push(pii(dist[e.to], e.to));
                    }
                }
            }
            if (dist[t] == INF)
                return -1;
            for (int v = 0; v < V; v++)
                h[v] += dist[v];
            capacity_type d = f;
            for (int v = t; v != s; v = prevv[v])
            {
                d = std::min(d, G[prevv[v]][preve[v]].cap);
            }
            f -= d;
            res += d * h[t];
            for (int v = t; v != s; v = prevv[v])
            {
                Edge &e = G[prevv[v]][preve[v]];
                e.cap -= d;
                G[v][e.rev].cap += d;
            }
        }
        return res;
    }
};

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    int n;
    cin >> n;
    ld x1, y1, r1, x2, y2, r2;
    cin >> x1 >> y1 >> r1 >> x2 >> y2 >> r2;
    Circle c1(Point(x1, y1), r1), c2(Point(x2, y2), r2);
    vector<Point> rs, bs;
    for (int i = 0; i < n; i++)
    {
        rs.push_back(input_point());
    }
    for (int i = 0; i < n; i++)
    {
        bs.push_back(input_point());
    }
    // dist[i][j] := rs[i], bs[j] の最短移動距離
    vector<vector<ld>> dist(n, vector<ld>(n, 1e15));
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            Line l = Line(rs[i], bs[j]);
            if (is_sc(c1, l).size() <= 1 && is_sc(c2, l).size() <= 1)
            {
                dist[i][j] = abs(rs[i] - bs[j]);
                continue;
            }
            // rs[i] から c1 への接線
            auto rl1 = tangent_cp(c1, rs[i]);
            // bs[j] から c1 への接線
            auto bl1 = tangent_cp(c1, bs[j]);
            // rs[i], c2 への接線
            auto rl2 = tangent_cp(c2, rs[i]);
            // bs[j], c2 への接線
            auto bl2 = tangent_cp(c2, bs[j]);
            for (auto l1 : rl1)
            {
                for (auto l2 : bl1)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c2, Line(rs[i], p)) || isContain(c2, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
            for (auto l1 : rl2)
            {
                for (auto l2 : bl2)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c1, Line(rs[i], p)) || isContain(c1, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
            // rs[i]-c1, bs[j]-c2
            for (auto l1 : rl1)
            {
                for (auto l2 : bl2)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c2, Line(rs[i], p)) || isContain(c1, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
            // rs[i]-c2, bs[j]-c1
            for (auto l1 : rl2)
            {
                for (auto l2 : bl1)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c1, Line(rs[i], p)) || isContain(c2, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
        }
    }
    minCostFlow mcf(2 * n + 2);
    for (int i = 0; i < n; i++)
    {
        mcf.add(0, i + 1, 1, 0);
        mcf.add(n + i + 1, 2 * n + 1, 1, 0);
        for (int j = 0; j < n; j++)
        {
            int st = i + 1, gt = n + 1 + j;
            if (dist[i][j] != 1e15)
            {
                mcf.add(st, gt, 1, dist[i][j]);
            }
        }
    }
    auto ret = mcf.calc(0, 2 * n + 1, n);
    if (ret == -1)
        cout << "Impossible" << endl;
    else
        cout << fixed << setprecision(10) << ret << endl;
}
accuracy: 1
time_ms: 30
memory_kb: 4096
final_rank: 3

code_snippet: #include "bits/stdc++.h"

using namespace std;

using ld = double;
using Point = std::complex<ld>;

const ld eps = 1e-9, pi = acos(-1.0);

namespace std
{
bool operator<(const Point &lhs, const Point &rhs)
{
    if (lhs.real() < rhs.real() - eps)
        return true;
    if (lhs.real() > rhs.real() + eps)
        return false;
    return lhs.imag() < rhs.imag();
}
} // namespace std

Point input_point()
{
    ld x, y;
    std::cin >> x >> y;
    return Point(x, y);
}

bool eq(ld a, ld b)
{
    return (abs(a - b) < eps);
}

ld dot(Point a, Point b)
{
    return real(conj(a) * b);
}

ld cross(Point a, Point b)
{
    return imag(conj(a) * b);
}

// CCW::counter clockwise
int ccw(Point a, Point b, Point c)
{
    b -= a;
    c -= a;
    if (cross(b, c) > eps)
        return 1; // a,b,c : counter-clockwise
    if (cross(b, c) < -eps)
        return -1; // a,b,c : clockwise
    if (dot(b, c) < 0)
        return 2; // c,a,b : on a line
    if (norm(b) < norm(c))
        return -2; // a,b,c : on a line
    return 0;      // a,c,b : on a line
}

class Line
{
public:
    Point a, b;
    Line() : a(Point(0, 0)), b(Point(0, 0)) {}
    Line(Point a, Point b) : a(a), b(b) {}
};

ld dot(Line l, Line m)
{
    return dot((l.a - l.b), (m.a - m.b));
}

// l:line, m:line が交点を持つか
bool isis_ll(Line l, Line m)
{
    return !eq(cross(l.b - l.a, m.b - m.a), 0);
}

// l:line, s:segment
bool isis_ls(Line l, Line s)
{
    return isis_ll(l, s) &&
           (cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}

// s:segment, t:segment
bool isis_ss(Line s, Line t)
{
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
           ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

// p が l:line 上に存在するか
bool isis_lp(Line l, Point p)
{
    return (abs(cross(l.b - p, l.a - p)) < eps);
}

bool isis_sp(Line s, Point p)
{
    return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}

// p から l に下ろした足との交点
Point proj(Line l, Point p)
{
    ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + t * (l.a - l.b);
}

// l:line, t:line の交点
Point is_ll(Line l, Line m)
{
    Point lv = l.b - l.a, mv = m.b - m.a;
    assert(cross(lv, mv) != 0);
    return l.a + lv * cross(mv, m.a - l.a) / cross(mv, lv);
}

// p, l:line の距離
ld dist_lp(Line l, Point p)
{
    return abs(p - proj(l, p));
}

ld dist_sp(Line s, Point p)
{
    Point r = proj(s, p);
    return isis_sp(s, r) ? abs(r - p) : std::min(abs(s.a - p), abs(s.b - p));
}

class Circle
{
public:
    Point p;
    ld r;
    Circle() : p(Point(0, 0)), r(0) {}
    Circle(Point p, ld r) : p(p), r(r) {}
};

std::vector<Point> is_lc(Circle c, Line l)
{
    std::vector<Point> res;
    ld d = dist_lp(l, c.p);
    if (d < c.r + eps)
    {
        ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d); //safety;
        Point nor = (l.a - l.b) / abs(l.a - l.b);
        res.emplace_back(proj(l, c.p) + len * nor);
        res.emplace_back(proj(l, c.p) - len * nor);
    }
    return res;
}

std::vector<Point> is_sc(Circle c, Line l)
{
    std::vector<Point> v = is_lc(c, l), res;
    for (Point p : v)
        if (isis_sp(l, p))
            res.emplace_back(p);
    return res;
}

// p から c への接線
std::vector<Line> tangent_cp(Circle c, Point p)
{
    std::vector<Line> ret;
    Point v = c.p - p;
    ld d = abs(v);
    ld l = sqrt(norm(v) - c.r * c.r);
    if (isnan((long double)l))
    {
        return ret;
    }
    Point v1 = v * Point(l / d, c.r / d);
    Point v2 = v * Point(l / d, -c.r / d);
    ret.emplace_back(Line(p, p + v1));
    if (l < eps)
        return ret;
    ret.emplace_back(Line(p, p + v2));
    return ret;
}

bool isContain(Circle c, Line l)
{
    return dist_sp(l, c.p) + eps < c.r;
}

class minCostFlow
{
    using capacity_type = int;
    using cost_type = double;
    using pii = std::pair<cost_type, int>;
    const int INF = 1e9;
    struct Edge
    {
        int to, rev;
        capacity_type cap;
        cost_type cost;
        Edge(int to_, int _rev, capacity_type cap_, cost_type cost_)
            : to(to_), rev(_rev), cap(cap_), cost(cost_) {}
    };
    int V;
    std::vector<std::vector<Edge>> G;
    // ポテンシャル
    std::vector<cost_type> h;
    // 最短距離
    std::vector<cost_type> dist;
    // 直前の頂点, 辺
    std::vector<int> prevv, preve;

public:
    minCostFlow(int _V) : V(_V), G(_V), h(_V), dist(_V), prevv(_V), preve(_V) {}
    void add(int from, int to, capacity_type cap, cost_type cost)
    {
        G[from].push_back(Edge(to, G[to].size(), cap, cost));
        G[to].push_back(Edge(from, G[from].size() - 1, 0, -cost));
    }
    cost_type calc(int s, int t, int f)
    {
        cost_type res = 0;
        fill(h.begin(), h.end(), 0);
        while (f > 0)
        {
            std::priority_queue<pii, std::vector<pii>, std::greater<pii>> que;
            fill(dist.begin(), dist.end(), INF);
            dist[s] = 0;
            que.push(pii(0, s));
            while (!que.empty())
            {
                pii p = que.top();
                que.pop();
                int v = p.second;
                if (dist[v] < p.first)
                    continue;
                for (size_t i = 0; i < G[v].size(); i++)
                {
                    Edge &e = G[v][i];
                    if (e.cap > eps && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to] + eps)
                    {
                        dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
                        prevv[e.to] = v;
                        preve[e.to] = i;
                        que.push(pii(dist[e.to], e.to));
                    }
                }
            }
            if (dist[t] == INF)
                return -1;
            for (int v = 0; v < V; v++)
                h[v] += dist[v];
            capacity_type d = f;
            for (int v = t; v != s; v = prevv[v])
            {
                d = std::min(d, G[prevv[v]][preve[v]].cap);
            }
            f -= d;
            res += d * h[t];
            for (int v = t; v != s; v = prevv[v])
            {
                Edge &e = G[prevv[v]][preve[v]];
                e.cap -= d;
                G[v][e.rev].cap += d;
            }
        }
        return res;
    }
};

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    int n;
    cin >> n;
    ld x1, y1, r1, x2, y2, r2;
    cin >> x1 >> y1 >> r1 >> x2 >> y2 >> r2;
    Circle c1(Point(x1, y1), r1), c2(Point(x2, y2), r2);
    vector<Point> rs, bs;
    for (int i = 0; i < n; i++)
    {
        rs.push_back(input_point());
    }
    for (int i = 0; i < n; i++)
    {
        bs.push_back(input_point());
    }
    // dist[i][j] := rs[i], bs[j] の最短移動距離
    vector<vector<ld>> dist(n, vector<ld>(n, 1e15));
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            Line l = Line(rs[i], bs[j]);
            if (is_sc(c1, l).size() <= 1 && is_sc(c2, l).size() <= 1)
            {
                dist[i][j] = abs(rs[i] - bs[j]);
                continue;
            }
            // rs[i] から c1 への接線
            auto rl1 = tangent_cp(c1, rs[i]);
            // bs[j] から c1 への接線
            auto bl1 = tangent_cp(c1, bs[j]);
            // rs[i], c2 への接線
            auto rl2 = tangent_cp(c2, rs[i]);
            // bs[j], c2 への接線
            auto bl2 = tangent_cp(c2, bs[j]);
            for (auto l1 : rl1)
            {
                for (auto l2 : bl1)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c2, Line(rs[i], p)) || isContain(c2, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
            for (auto l1 : rl2)
            {
                for (auto l2 : bl2)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c1, Line(rs[i], p)) || isContain(c1, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
            // rs[i]-c1, bs[j]-c2
            for (auto l1 : rl1)
            {
                for (auto l2 : bl2)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c2, Line(rs[i], p)) || isContain(c1, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
            // rs[i]-c2, bs[j]-c1
            for (auto l1 : rl2)
            {
                for (auto l2 : bl1)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c1, Line(rs[i], p)) || isContain(c2, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
        }
    }
    minCostFlow mcf(2 * n + 2);
    for (int i = 0; i < n; i++)
    {
        mcf.add(0, i + 1, 1, 0);
        mcf.add(n + i + 1, 2 * n + 1, 1, 0);
        for (int j = 0; j < n; j++)
        {
            int st = i + 1, gt = n + 1 + j;
            if (dist[i][j] != 1e15)
            {
                mcf.add(st, gt, 1, dist[i][j]);
            }
        }
    }
    auto ret = mcf.calc(0, 2 * n + 1, n);
    if (ret == -1)
        cout << "Impossible" << endl;
    else
        cout << fixed << setprecision(10) << ret << endl;
}
accuracy: 1
time_ms: 30
memory_kb: 4096
final_rank: 3

code_snippet: #include "bits/stdc++.h"

using namespace std;

using ld = long double;
using Point = std::complex<ld>;

const ld eps = 1e-9, pi = acos(-1.0);

namespace std
{
bool operator<(const Point &lhs, const Point &rhs)
{
    if (lhs.real() < rhs.real() - eps)
        return true;
    if (lhs.real() > rhs.real() + eps)
        return false;
    return lhs.imag() < rhs.imag();
}
} // namespace std

Point input_point()
{
    ld x, y;
    std::cin >> x >> y;
    return Point(x, y);
}

bool eq(ld a, ld b)
{
    return (abs(a - b) < eps);
}

ld dot(Point a, Point b)
{
    return real(conj(a) * b);
}

ld cross(Point a, Point b)
{
    return imag(conj(a) * b);
}

// CCW::counter clockwise
int ccw(Point a, Point b, Point c)
{
    b -= a;
    c -= a;
    if (cross(b, c) > eps)
        return 1; // a,b,c : counter-clockwise
    if (cross(b, c) < -eps)
        return -1; // a,b,c : clockwise
    if (dot(b, c) < 0)
        return 2; // c,a,b : on a line
    if (norm(b) < norm(c))
        return -2; // a,b,c : on a line
    return 0;      // a,c,b : on a line
}

class Line
{
public:
    Point a, b;
    Line() : a(Point(0, 0)), b(Point(0, 0)) {}
    Line(Point a, Point b) : a(a), b(b) {}
};

ld dot(Line l, Line m)
{
    return dot((l.a - l.b), (m.a - m.b));
}

// l:line, m:line が交点を持つか
bool isis_ll(Line l, Line m)
{
    return !eq(cross(l.b - l.a, m.b - m.a), 0);
}

// l:line, s:segment
bool isis_ls(Line l, Line s)
{
    return isis_ll(l, s) &&
           (cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}

// s:segment, t:segment
bool isis_ss(Line s, Line t)
{
    return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
           ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

// p が l:line 上に存在するか
bool isis_lp(Line l, Point p)
{
    return (abs(cross(l.b - p, l.a - p)) < eps);
}

bool isis_sp(Line s, Point p)
{
    return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}

// p から l に下ろした足との交点
Point proj(Line l, Point p)
{
    ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + t * (l.a - l.b);
}

// l:line, t:line の交点
Point is_ll(Line l, Line m)
{
    Point lv = l.b - l.a, mv = m.b - m.a;
    assert(cross(lv, mv) != 0);
    return l.a + lv * cross(mv, m.a - l.a) / cross(mv, lv);
}

// p, l:line の距離
ld dist_lp(Line l, Point p)
{
    return abs(p - proj(l, p));
}

ld dist_ll(Line l, Line m)
{
    return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}

ld dist_ls(Line l, Line s)
{
    return isis_ls(l, s) ? 0 : std::min(dist_lp(l, s.a), dist_lp(l, s.b));
}

ld dist_sp(Line s, Point p)
{
    Point r = proj(s, p);
    return isis_sp(s, r) ? abs(r - p) : std::min(abs(s.a - p), abs(s.b - p));
}

ld dist_ss(Line s, Line t)
{
    if (isis_ss(s, t))
        return 0;
    return std::min({dist_sp(s, t.a), dist_sp(s, t.b), dist_sp(t, s.a), dist_sp(t, s.b)});
}

class Circle
{
public:
    Point p;
    ld r;
    Circle() : p(Point(0, 0)), r(0) {}
    Circle(Point p, ld r) : p(p), r(r) {}
};

// c1, c2 の交点
std::vector<Point> is_cc(Circle c1, Circle c2)
{
    std::vector<Point> res;
    ld d = abs(c1.p - c2.p);
    ld rc = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
    ld dfr = c1.r * c1.r - rc * rc;
    if (abs(dfr) < eps)
        dfr = 0.0;
    else if (dfr < 0.0)
        return res; // no intersection
    ld rs = sqrt(dfr);
    Point diff = (c2.p - c1.p) / d;
    res.emplace_back(c1.p + diff * Point(rc, rs));
    if (dfr != 0.0)
        res.emplace_back(c1.p + diff * Point(rc, -rs));
    return res;
}

std::vector<Point> is_lc(Circle c, Line l)
{
    std::vector<Point> res;
    ld d = dist_lp(l, c.p);
    if (d < c.r + eps)
    {
        ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d); //safety;
        Point nor = (l.a - l.b) / abs(l.a - l.b);
        res.emplace_back(proj(l, c.p) + len * nor);
        res.emplace_back(proj(l, c.p) - len * nor);
    }
    return res;
}

std::vector<Point> is_sc(Circle c, Line l)
{
    std::vector<Point> v = is_lc(c, l), res;
    for (Point p : v)
        if (isis_sp(l, p))
            res.emplace_back(p);
    return res;
}

// p から c への接線
std::vector<Line> tangent_cp(Circle c, Point p)
{
    std::vector<Line> ret;
    Point v = c.p - p;
    ld d = abs(v);
    ld l = sqrt(norm(v) - c.r * c.r);
    if (isnan(l))
    {
        return ret;
    }
    Point v1 = v * Point(l / d, c.r / d);
    Point v2 = v * Point(l / d, -c.r / d);
    ret.emplace_back(Line(p, p + v1));
    if (l < eps)
        return ret;
    ret.emplace_back(Line(p, p + v2));
    return ret;
}

bool isContain(Circle c, Line l)
{
    // l が c と交差するか(交点が２個以上か)
    return dist_sp(l, c.p) + eps < c.r;
}

struct Edge
{
    using cost_type = ld;
    using capacity_type = int;
    int to, rev;
    capacity_type cap;
    cost_type cost;
    Edge(int _to, int _rev, capacity_type _cap, cost_type _cost) : to(_to), rev(_rev), cap(_cap), cost(_cost) {}
};

void add_edge(vector<vector<Edge>> &g, int from, int to, Edge::capacity_type cap, Edge::cost_type cost)
{
    g[from].emplace_back(to, static_cast<int>(g[to].size()), cap, cost);
    g[to].emplace_back(from, static_cast<int>(g[from].size() - 1), Edge::capacity_type{0}, -cost);
}

template <typename Edge>
typename Edge::cost_type min_cost_flow(vector<vector<Edge>> &g, int s, int t, typename Edge::capacity_type f)
{
    using cost_type = typename Edge::cost_type;
    using P = std::pair<cost_type, int>;
    const auto inf = std::numeric_limits<cost_type>::max() / 2;
    cost_type res = 0;
    std::vector<cost_type> h(g.size()), dist(g.size());
    std::vector<int> prevv(g.size()), preve(g.size());
    while (f > 0)
    {
        std::priority_queue<P, std::vector<P>, std::greater<>> que;
        std::fill(std::begin(dist), std::end(dist), inf);
        dist[s] = 0;
        que.emplace(dist[s], s);
        while (!que.empty())
        {
            const auto cur_d = que.top().first;
            const int v = que.top().second;
            que.pop();
            if (dist[v] < cur_d)
                continue;
            for (int i = 0; i < (int)g[v].size(); ++i)
            {
                auto &e = g[v][i];
                if (e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to])
                {
                    dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
                    prevv[e.to] = v;
                    preve[e.to] = i;
                    que.emplace(dist[e.to], e.to);
                }
            }
        }
        if (dist[t] == inf)
            return -1;
        for (int v = 0; v < (int)g.size(); ++v)
        {
            h[v] += dist[v];
        }

        auto d = f;
        for (int v = t; v != s; v = prevv[v])
        {
            d = std::min(d, g[prevv[v]][preve[v]].cap);
        }
        f -= d;
        res += d * h[t];
        for (int v = t; v != s; v = prevv[v])
        {
            auto &e = g[prevv[v]][preve[v]];
            e.cap -= d;
            g[v][e.rev].cap += d;
        }
    }
    return res;
}

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    int n;
    cin >> n;
    ld x1, y1, r1, x2, y2, r2;
    cin >> x1 >> y1 >> r1 >> x2 >> y2 >> r2;
    Circle c1(Point(x1, y1), r1), c2(Point(x2, y2), r2);
    vector<Point> rs, bs;
    for (int i = 0; i < n; i++)
    {
        rs.push_back(input_point());
    }
    for (int i = 0; i < n; i++)
    {
        bs.push_back(input_point());
    }
    // dist[i][j] := rs[i], bs[j] の最短移動距離
    vector<vector<ld>> dist(n, vector<ld>(n, 1e15));
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            Line l = Line(rs[i], bs[j]);
            if (is_sc(c1, l).size() <= 1 && is_sc(c2, l).size() <= 1)
            {
                dist[i][j] = abs(rs[i] - bs[j]);
                continue;
            }
            // rs[i] から c1 への接線
            auto rl1 = tangent_cp(c1, rs[i]);
            // bs[j] から c1 への接線
            auto bl1 = tangent_cp(c1, bs[j]);
            // rs[i], c2 への接線
            auto rl2 = tangent_cp(c2, rs[i]);
            // bs[j], c2 への接線
            auto bl2 = tangent_cp(c2, bs[j]);
            for (auto l1 : rl1)
            {
                for (auto l2 : bl1)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c2, Line(rs[i], p)) || isContain(c2, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
            for (auto l1 : rl2)
            {
                for (auto l2 : bl2)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c1, Line(rs[i], p)) || isContain(c1, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
            // rs[i]-c1, bs[j]-c2
            for (auto l1 : rl1)
            {
                for (auto l2 : bl2)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c2, Line(rs[i], p)) || isContain(c1, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
            // rs[i]-c2, bs[j]-c1
            for (auto l1 : rl2)
            {
                for (auto l2 : bl1)
                {
                    Point lv = l1.b - l1.a, mv = l2.b - l2.a;
                    if (cross(lv, mv) == 0)
                        continue;
                    Point p = is_ll(l1, l2);
                    if (isContain(c1, Line(rs[i], p)) || isContain(c2, Line(bs[j], p)))
                        continue;
                    dist[i][j] = min(dist[i][j], abs(p - rs[i]) + abs(p - bs[j]));
                }
            }
        }
    }
    vector<vector<Edge>> g(2 * n + 2);
    for (int i = 0; i < n; i++)
    {
        add_edge(g, 0, i + 1, 1, 0);
        add_edge(g, n + i + 1, 2 * n + 1, 1, 0);
        for (int j = 0; j < n; j++)
        {
            int st = i + 1, gt = n + 1 + i;
            add_edge(g, st, gt, 1, dist[i][j]);
            // cout << i << " " << j << " " << dist[i][j] << endl;
        }
    }
    auto ret = min_cost_flow<Edge>(g, 0, 2 * n + 1, (Edge::capacity_type)n);
    if (ret > 100000)
        cout << "Impossible" << endl;
    else
        cout << fixed << setprecision(10) << ret << endl;
}
accuracy: 0.21875
time_ms: 40
memory_kb: 4108
final_rank: 10

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<utility>
#include<map>
#include<complex>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
typedef pair<ll, ll> LP;
typedef vector<int> vec;
#define rep(i,n) for(int i=0;i<n;i++)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define stop char nyaa;cin>>nyaa;
#define per(i,n) for(int i=n-1;i>=0;i--)

//geometry
typedef long double ld;
typedef complex<ld> Point;
const ld pi = acos(-1.0);
const ld eps = 1e-9;

bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
ld dot(Point a, Point b) { return real(conj(a)*b); }
ld cross(Point a, Point b) { return imag(conj(a)*b); }

struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}

Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a;
	Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

vector<Line> tangent_cp(Circle c, Point p) {
	vector<Line> res;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r*c.r);
	if (isnan(l))return res;
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	res.push_back(Line{ p,p + v1 });
	if (l < eps)return res;
	res.push_back(Line{ p,p + v2 });
	return res;
}

int max_n;
const int mn = 100000;
struct edge {
	int to, cap; ld cost; int rev;
};
typedef pair<ld, int> speP;
vector<edge> G[mn];
int par[mn];
ld dist[mn];
void add_edge(int from, int to, int cap, ld cost) {
	G[from].push_back({ to,cap,cost,(int)G[to].size() });
	G[to].push_back({ from,0,-cost,(int)G[from].size()-1 });
	max_n = max({ max_n,from + 1,to + 1 });
}
ld minimum_road(int s, int t) {
	fill(par, par + max_n, -1);
	fill(dist, dist + max_n, mod);
	dist[s] = 0;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,s });
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (id == t)continue;
		if (p.first > dist[id])continue;
		rep(j, G[id].size()) {
			if (G[id][j].cap > 0) {
				int to = G[id][j].to;
				ld nd = p.first + G[id][j].cost;
				if (nd < dist[to]) {
					dist[to] = nd;
					par[to] = id;
					q.push({ dist[to],to });
				}
			}
		}
	}
	int cur = t;
	while (cur != s) {
		int p = par[cur];
		if (p < 0)return -1;
		rep(j, G[p].size()) {
			if (G[p][j].cap > 0 && G[p][j].to == cur && dist[p] + G[p][j].cost == dist[cur]) {
				G[p][j].cap--;
				G[cur][G[p][j].rev].cap++;
				break;
			}
		}
		cur = p;
	}
	return dist[t];
}
ld minimum_cost_flow(int s, int t, int k) {
	ld ret = 0;
	rep(i, k) {
		ld z = minimum_road(s, t);
		if (z < 0)return -1;
		ret += z;
	}
	return ret;
}

bool isis_cs(Circle c, Line s) {
	ld dist = dist_sp(s,c.p);
	return dist < c.r - eps;
}

vector<Circle> c;

void solve() {
	int n; cin >> n;
	c.resize(2);
	rep(i, 2) {
		ld x, y, r; cin >> x >> y >> r;
		c[i] = { {x,y},r };
	}
	vector<Point> a(n), b(n);
	rep(i, n) {
		ld x, y; cin >> x >> y;
		a[i] = { x,y };
	}
	rep(i, n) {
		ld x, y; cin >> x >> y;
		b[i] = { x,y };
	}
	int s = 2 * n, t = 2 * n + 1;
	rep(i, n) {
		add_edge(s, i, 1, 0);
		add_edge(i + n,t, 1, 0);
	}
	vector<vector<Line>> l(n), r(n);
	rep(i, n) {
		rep(j, 2) {
			vector<Line> u = tangent_cp(c[j], a[i]);
			rep(k, u.size())l[i].push_back(u[k]);
			u = tangent_cp(c[j], b[i]);
			rep(k, u.size())r[i].push_back(u[k]);
		}
	}
	rep(i, n) {
		rep(j, n) {
			Point le = a[i], ri = b[j];
			ld cost = mod;
			{
				Line l = { le,ri };
				bool f = true;
				rep(k, 2) {
					if (isis_cs(c[k], l))f = false;
				}
				if (f) {
					cost = abs(ri - le);
					add_edge(i, n + j, 1, cost);
					continue;
				}
			}
			rep(k1, l[i].size()) {
				rep(k2,r[j].size()) {
					Line lle = l[i][k1];
					Line rri = r[j][k2];
					if (!isis_ll(lle, rri))continue;
					Point cn = is_ll(lle, rri);
					Line sl = { le,cn };
					Line sr = { ri,cn };
					bool valid = true;
					rep(k, 2) {
						if (isis_cs(c[k], sl) || isis_cs(c[k], sr)) {
							valid = false; break;
						}
					}
					if (valid) {
						cost = min(cost, abs(cn - le) + abs(cn - ri));
					}
				}
			}
			if (cost == mod)continue;
			add_edge(i, n + j, 1, cost);
		}
	}
	ld ans = minimum_cost_flow(s, t, n);
	if (ans == -1) {
		cout << "Impossible" << endl;
	}
	else {
		cout << ans << endl;
	}
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	solve();
	//stop
		return 0;
}
accuracy: 1
time_ms: 150
memory_kb: 7156
final_rank: 7

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<utility>
#include<map>
#include<complex>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
typedef pair<ll, ll> LP;
typedef vector<int> vec;
#define rep(i,n) for(int i=0;i<n;i++)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define stop char nyaa;cin>>nyaa;
#define per(i,n) for(int i=n-1;i>=0;i--)

//geometry
typedef long double ld;
typedef complex<ld> Point;
const ld pi = acos(-1.0);
const ld eps = 1e-10;

bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
ld dot(Point a, Point b) { return real(conj(a)*b); }
ld cross(Point a, Point b) { return imag(conj(a)*b); }

struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}

Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a;
	Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

vector<Line> tangent_cp(Circle c, Point p) {
	vector<Line> res;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r*c.r);
	if (isnan(l))return res;
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	res.push_back(Line{ p,p + v1 });
	if (l < eps)return res;
	res.push_back(Line{ p,p + v2 });
	return res;
}

int max_n;
const int mn = 100000;
struct edge {
	int to, cap; ld cost; int rev;
};
typedef pair<ld, int> speP;
vector<edge> G[mn];
int par[mn];
ld dist[mn];
void add_edge(int from, int to, int cap, ld cost) {
	G[from].push_back({ to,cap,cost,(int)G[to].size() });
	G[to].push_back({ from,0,-cost,(int)G[from].size()-1 });
	max_n = max({ max_n,from + 1,to + 1 });
}
ld minimum_road(int s, int t) {
	fill(par, par + max_n, -1);
	fill(dist, dist + max_n, mod);
	dist[s] = 0;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,s });
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (id == t)continue;
		if (p.first > dist[id])continue;
		rep(j, G[id].size()) {
			if (G[id][j].cap > 0) {
				int to = G[id][j].to;
				ld nd = p.first + G[id][j].cost;
				if (nd < dist[to]) {
					dist[to] = nd;
					par[to] = id;
					q.push({ dist[to],to });
				}
			}
		}
	}
	int cur = t;
	while (cur != s) {
		int p = par[cur];
		if (p < 0)return -1;
		rep(j, G[p].size()) {
			if (G[p][j].cap > 0 && G[p][j].to == cur && dist[p] + G[p][j].cost == dist[cur]) {
				G[p][j].cap--;
				G[cur][G[p][j].rev].cap++;
				break;
			}
		}
		cur = p;
	}
	return dist[t];
}
ld minimum_cost_flow(int s, int t, int k) {
	ld ret = 0;
	rep(i, k) {
		ld z = minimum_road(s, t);
		if (z < 0)return -1;
		ret += z;
	}
	return ret;
}

bool isis_cs(Circle c, Line s) {
	ld dist = dist_sp(s,c.p);
	return dist < c.r - eps;
}

vector<Circle> c;

void solve() {
	int n; cin >> n;
	c.resize(2);
	rep(i, 2) {
		ld x, y, r; cin >> x >> y >> r;
		c[i] = { {x,y},r };
	}
	vector<Point> a(n), b(n);
	rep(i, n) {
		ld x, y; cin >> x >> y;
		a[i] = { x,y };
	}
	rep(i, n) {
		ld x, y; cin >> x >> y;
		b[i] = { x,y };
	}
	int s = 2 * n, t = 2 * n + 1;
	rep(i, n) {
		add_edge(s, i, 1, 0);
		add_edge(i + n,t, 1, 0);
	}
	vector<vector<Line>> l(n), r(n);
	rep(i, n) {
		rep(j, 2) {
			vector<Line> u = tangent_cp(c[j], a[i]);
			rep(k, u.size())l[i].push_back(u[k]);
			u = tangent_cp(c[j], b[i]);
			rep(k, u.size())r[i].push_back(u[k]);
		}
	}
	rep(i, n) {
		rep(j, n) {
			Point le = a[i], ri = b[j];
			ld cost = mod;
			{
				Line l = { le,ri };
				bool f = true;
				rep(k, 2) {
					if (isis_cs(c[k], l))f = false;
				}
				if (f) {
					cost = abs(ri - le);
					add_edge(i, n + j, 1, cost);
					continue;
				}
			}
			rep(k1, l[i].size()) {
				rep(k2,r[j].size()) {
					Line lle = l[i][k1];
					Line rri = r[j][k2];
					if (!isis_ll(lle, rri))continue;
					Point cn = is_ll(lle, rri);
					Line sl = { le,cn };
					Line sr = { ri,cn };
					bool valid = true;
					rep(k, 2) {
						if (isis_cs(c[k], sl) || isis_cs(c[k], sr)) {
							valid = false; break;
						}
					}
					if (valid) {
						cost = min(cost, abs(cn - le) + abs(cn - ri));
					}
				}
			}
			if (cost == mod)continue;
			add_edge(i, n + j, 1, cost);
		}
	}
	ld ans = minimum_cost_flow(s, t, n);
	if (ans == -1||ans>10000+eps) {
		cout << "Impossible" << endl;
	}
	else {
		cout << ans << endl;
	}
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	solve();
	//stop
		return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 7048
final_rank: 8

code_snippet: #include "bits/stdc++.h"
using namespace std;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))
static const int INF = 0x3f3f3f3f; static const long long INFL = 0x3f3f3f3f3f3f3f3fLL;
typedef vector<int> vi; typedef pair<int, int> pii; typedef vector<pair<int, int> > vpii; typedef long long ll;
template<typename T, typename U> static void amin(T &x, U y) { if(y < x) x = y; }
template<typename T, typename U> static void amax(T &x, U y) { if(x < y) x = y; }
 
const double EPS = 1e-9;
 
const double InfCost = 1e99;
struct MinimumCostMaximumFlow {
    typedef int Index; typedef int Flow; typedef double Cost;
    static const Flow InfCapacity = INF;
    struct Edge {
        Index to; Index rev;
        Flow capacity; Cost cost;
    };
    vector<vector<Edge> > g;
    void init(Index n) { g.assign(n, vector<Edge>()); }
    void add(Index i, Index j, Flow capacity = InfCapacity, Cost cost = Cost()) {
        Edge e, f; e.to = j, f.to = i; e.capacity = capacity, f.capacity = 0; e.cost = cost, f.cost = -cost;
        g[i].push_back(e); g[j].push_back(f);
        g[i].back().rev = (Index)g[j].size() - 1; g[j].back().rev = (Index)g[i].size() - 1;
    }
    void addB(Index i, Index j, Flow capacity = InfCapacity, Cost cost = Cost()) {
        add(i, j, capacity, cost);
        add(j, i, capacity, cost);
    }
    pair<Cost, Flow> minimumCostMaximumFlow(Index s, Index t, Flow f = InfCapacity, bool bellmanFord = false) {
        int n = g.size();
        vector<Cost> dist(n); vector<Index> prev(n); vector<Index> prevEdge(n);
        pair<Cost, Flow> total = make_pair(0, 0);
        vector<Cost> potential(n);
        while(f > 0) {
            fill(dist.begin(), dist.end(), InfCost);
            if(bellmanFord || total.second == 0) {
                dist[s] = 0;
                rep(k, n) {
                    bool update = false;
                    rep(i, n) if(dist[i] != InfCost)
                        for(Index ei = 0; ei < (Index)g[i].size(); ei ++) {
                            const Edge &e = g[i][ei];
                            if(e.capacity <= 0) continue;
                            Index j = e.to; Cost d = dist[i] + e.cost;
                            if(dist[j] > d + EPS) {  //?????????
                                dist[j] = d; prev[j] = i; prevEdge[j] = ei;
                                update = true;
                            }
                        }
                    if(!update) break;
                }
            } else {
                vector<bool> vis(n);
                priority_queue<pair<Cost, Index> > q;
                q.push(make_pair(-0, s)); dist[s] = 0;
                while(!q.empty()) {
                    Index i = q.top().second; q.pop();
                    if(vis[i]) continue;
                    vis[i] = true;
                    for(Index ei = 0; ei < (Index)g[i].size(); ei ++) {
                        const Edge &e = g[i][ei];
                        if(e.capacity <= 0) continue;
                        Index j = e.to; Cost d = dist[i] + e.cost + potential[i] - potential[j];
                        if(d < dist[i])  d = dist[i];    //?????????
                        if(dist[j] > d) {
                            dist[j] = d; prev[j] = i; prevEdge[j] = ei;
                            q.push(make_pair(-d, j));
                        }
                    }
                }
            }
            if(dist[t] == InfCost) break;
            if(!bellmanFord) for(Index i = 0; i < n; i ++) potential[i] += dist[i];
            Flow d = f; Cost distt = 0;
            for(Index v = t; v != s; ) {
                Index u = prev[v]; const Edge &e = g[u][prevEdge[v]];
                d = min(d, e.capacity); distt += e.cost; v = u;
            }
            f -= d; total.first += d * distt; total.second += d;
            for(Index v = t; v != s; v = prev[v]) {
                Edge &e = g[prev[v]][prevEdge[v]];
                e.capacity -= d; g[e.to][e.rev].capacity += d;
            }
        }
        return total;
    }
};
 
 
typedef complex<double> Point;
 
double dot(Point a, Point b) {
    return (a * conj(b)).real();
}
 
double cross(Point a, Point b) {
    return (a * conj(b)).imag();
}
 
struct Line {
    Point a, b;
};
struct Circle {
    Point p;
    double r;
};
 
void tangentCP(const Circle &c, const Point &p, vector<Point> &res) {
    Point v = c.p - p;
    auto d = abs(v), l = sqrt(max(0., norm(v) - c.r * c.r));
    Point t = Point(l / d, c.r / d);
    res.push_back(v * t);
    if(l > 1e-9)
        res.push_back(v * conj(t));
}
 
Point crosspoint(const Line &a, const Line &b) {
    auto A = cross(a.b - a.a, b.b - b.a), B = cross(a.b - a.a, a.b - b.a);
    return b.a + B / A * (b.b - b.a);
}
 
Point projection(const Line &l, const Point &p) {
    double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
    return l.a + t * (l.a - l.b);
}
 
bool intersectSP(const Line &s, const Point &p) {
    return abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) <= EPS;
}
 
double distanceSP(const Line &s, const Point &p) {
    const Point r = projection(s, p);
    if(intersectSP(s, r)) { return abs(r - p); }
    return min(abs(s.a - p), abs(s.b - p));
}
 
int main() {
    int n;
    while(~scanf("%d", &n)) {
        Circle circles[2];
        rep(k, 2) {
            double x, y, r;
            scanf("%lf%lf%lf", &x, &y, &r);
            circles[k] = { {x, y}, r };
        }
        vector<Point> points(n * 2);
        rep(i, n * 2) {
            double x, y;
            scanf("%lf%lf", &x, &y);
            points[i] = { x,y };
        }
        vector<vector<Point>> tangents(n * 2);
        rep(i, n * 2) {
            rep(k, 2)
                tangentCP(circles[k], points[i], tangents[i]);
        }
        vector<Point> vsA, vsB;
        int src = n * 2, dst = src + 1;
        MinimumCostMaximumFlow mcmf;
        mcmf.init(dst + 1);
        rep(i, n) {
            mcmf.add(src, i, 1);
            mcmf.add(n + i, dst, 1);
        }
        rep(i, n) reu(j, n, n * 2) {
            vsA = tangents[i];
            vsB = tangents[j];
            vsA.push_back(points[j] - points[i]);
            vsB.push_back(points[i] - points[j]);
            double dist = 1e99;
            for(auto v : vsA) for(auto w : vsB) {
                Point x =
                    abs(cross(v, w)) <= EPS ?
                    (points[i] + points[j]) * .5 :
                    crosspoint(Line{ points[i], points[i] + v }, Line{ points[j], points[j] + w });
                Line s{ points[i], x }, t{ points[j], x };
                bool ok = true;
                for(const Circle &c : circles) {
                    ok &= distanceSP(s, c.p) >= c.r - EPS;
                    ok &= distanceSP(t, c.p) >= c.r - EPS;
                }
                if(ok)
                    amin(dist, abs(s.b - s.a) + abs(t.b - t.a));
            }
            if(dist < 1e99)
                mcmf.add(i, j, 1, dist);
        }
        auto fp = mcmf.minimumCostMaximumFlow(src, dst, n);
        if(fp.second != n) {
            puts("Impossible");
        } else {
            printf("%.10f\n", fp.first);
        }
    }
    return 0;
}
accuracy: 0.21875
time_ms: 80
memory_kb: 3804
final_rank: 12

code_snippet: #include "bits/stdc++.h"
using namespace std;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))
static const int INF = 0x3f3f3f3f; static const long long INFL = 0x3f3f3f3f3f3f3f3fLL;
typedef vector<int> vi; typedef pair<int, int> pii; typedef vector<pair<int, int> > vpii; typedef long long ll;
template<typename T, typename U> static void amin(T &x, U y) { if(y < x) x = y; }
template<typename T, typename U> static void amax(T &x, U y) { if(x < y) x = y; }

const double EPS = 1e-9;

const double InfCost = 1e99;
struct MinimumCostMaximumFlow {
	typedef int Index; typedef int Flow; typedef double Cost;
	static const Flow InfCapacity = INF;
	struct Edge {
		Index to; Index rev;
		Flow capacity; Cost cost;
	};
	vector<vector<Edge> > g;
	void init(Index n) { g.assign(n, vector<Edge>()); }
	void add(Index i, Index j, Flow capacity = InfCapacity, Cost cost = Cost()) {
		Edge e, f; e.to = j, f.to = i; e.capacity = capacity, f.capacity = 0; e.cost = cost, f.cost = -cost;
		g[i].push_back(e); g[j].push_back(f);
		g[i].back().rev = (Index)g[j].size() - 1; g[j].back().rev = (Index)g[i].size() - 1;
	}
	void addB(Index i, Index j, Flow capacity = InfCapacity, Cost cost = Cost()) {
		add(i, j, capacity, cost);
		add(j, i, capacity, cost);
	}
	pair<Cost, Flow> minimumCostMaximumFlow(Index s, Index t, Flow f = InfCapacity, bool bellmanFord = false) {
		int n = g.size();
		vector<Cost> dist(n); vector<Index> prev(n); vector<Index> prevEdge(n);
		pair<Cost, Flow> total = make_pair(0, 0);
		vector<Cost> potential(n);
		while(f > 0) {
			fill(dist.begin(), dist.end(), InfCost);
			if(bellmanFord || total.second == 0) {
				dist[s] = 0;
				rep(k, n) {
					bool update = false;
					rep(i, n) if(dist[i] != InfCost)
						for(Index ei = 0; ei < (Index)g[i].size(); ei ++) {
							const Edge &e = g[i][ei];
							if(e.capacity <= 0) continue;
							Index j = e.to; Cost d = dist[i] + e.cost;
							if(dist[j] > d + EPS) {	//?????????
								dist[j] = d; prev[j] = i; prevEdge[j] = ei;
								update = true;
							}
						}
					if(!update) break;
				}
			} else {
				vector<bool> vis(n);
				priority_queue<pair<Cost, Index> > q;
				q.push(make_pair(-0, s)); dist[s] = 0;
				while(!q.empty()) {
					Index i = q.top().second; q.pop();
					if(vis[i]) continue;
					vis[i] = true;
					for(Index ei = 0; ei < (Index)g[i].size(); ei ++) {
						const Edge &e = g[i][ei];
						if(e.capacity <= 0) continue;
						Index j = e.to; Cost d = dist[i] + e.cost + potential[i] - potential[j];
						if(d < dist[i])	d = dist[i];	//?????????
						if(dist[j] > d) {
							dist[j] = d; prev[j] = i; prevEdge[j] = ei;
							q.push(make_pair(-d, j));
						}
					}
				}
			}
			if(dist[t] == InfCost) break;
			if(!bellmanFord) for(Index i = 0; i < n; i ++) potential[i] += dist[i];
			Flow d = f; Cost distt = 0;
			for(Index v = t; v != s; ) {
				Index u = prev[v]; const Edge &e = g[u][prevEdge[v]];
				d = min(d, e.capacity); distt += e.cost; v = u;
			}
			f -= d; total.first += d * distt; total.second += d;
			for(Index v = t; v != s; v = prev[v]) {
				Edge &e = g[prev[v]][prevEdge[v]];
				e.capacity -= d; g[e.to][e.rev].capacity += d;
			}
		}
		return total;
	}
};


typedef complex<double> Point;

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

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

struct Line {
	Point a, b;
};
struct Circle {
	Point p;
	double r;
};

void tangentCP(const Circle &c, const Point &p, vector<Point> &res) {
	Point v = c.p - p;
	auto d = abs(v), l = sqrt(max(0., norm(v) - c.r * c.r));
	Point t = Point(l / d, c.r / d);
	res.push_back(v * t);
	if(l > 1e-9)
		res.push_back(v * conj(t));
}

Point crosspoint(const Line &a, const Line &b) {
	auto A = cross(a.b - a.a, b.b - b.a), B = cross(a.b - a.a, a.b - b.a);
	return b.a + B / A * (b.b - b.a);
}

Point projection(const Line &l, const Point &p) {
	double t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}

bool intersectSP(const Line &s, const Point &p) {
	return abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) <= EPS;
}

double distanceSP(const Line &s, const Point &p) {
	const Point r = projection(s, p);
	if(intersectSP(s, r)) { return abs(r - p); }
	return min(abs(s.a - p), abs(s.b - p));
}

int main() {
	int n;
	while(~scanf("%d", &n)) {
		Circle circles[2];
		rep(k, 2) {
			double x, y, r;
			scanf("%lf%lf%lf", &x, &y, &r);
			circles[k] = { {x, y}, r };
		}
		vector<Point> points(n * 2);
		rep(i, n * 2) {
			double x, y;
			scanf("%lf%lf", &x, &y);
			points[i] = { x,y };
		}
		vector<vector<Point>> tangents(n * 2);
		rep(i, n * 2) {
			rep(k, 2)
				tangentCP(circles[k], points[i], tangents[i]);
		}
		vector<Point> vsA, vsB;
		int src = n * 2, dst = src + 1;
		MinimumCostMaximumFlow mcmf;
		mcmf.init(dst + 1);
		rep(i, n) {
			mcmf.add(src, i, 1);
			mcmf.add(n + i, dst, 1);
		}
		rep(i, n) reu(j, n, n * 2) {
			vsA = tangents[i];
			vsB = tangents[j];
			vsA.push_back(points[j] - points[i]);
			vsB.push_back(points[i] - points[j]);
			double dist = 1e99;
			for(auto v : vsA) for(auto w : vsB) {
				Point x =
					abs(cross(v, w)) <= EPS ?
					(points[i] + points[j]) * .5 :
					crosspoint(Line{ points[i], points[i] + v }, Line{ points[j], points[j] + w });
				Line s{ points[i], x }, t{ points[j], x };
				bool ok = true;
				for(const Circle &c : circles) {
					ok &= distanceSP(s, c.p) >= c.r - EPS;
					ok &= distanceSP(t, c.p) >= c.r - EPS;
				}
				if(ok)
					amin(dist, abs(s.b - s.a) + abs(t.b - t.a));
			}
			if(dist < 1e99)
				mcmf.add(i, j, 1, dist);
		}
		auto fp = mcmf.minimumCostMaximumFlow(src, dst, n);
		if(fp.second != n) {
			puts("Impossible");
		} else {
			printf("%.10f\n", fp.first);
		}
	}
	return 0;
}
accuracy: 0.21875
time_ms: 80
memory_kb: 3752
final_rank: 11

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<utility>
#include<map>
#include<complex>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
typedef pair<ll, ll> LP;
typedef vector<int> vec;
#define rep(i,n) for(int i=0;i<n;i++)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define stop char nyaa;cin>>nyaa;
#define per(i,n) for(int i=n-1;i>=0;i--)

//geometry
typedef long double ld;
typedef complex<ld> Point;
const ld pi = acos(-1.0);
const ld eps = 1e-10;

bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
ld dot(Point a, Point b) { return real(conj(a)*b); }
ld cross(Point a, Point b) { return imag(conj(a)*b); }

struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}

Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a;
	Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

vector<Line> tangent_cp(Circle c, Point p) {
	vector<Line> res;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r*c.r);
	if (isnan(l))return res;
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	res.push_back(Line{ p,p + v1 });
	if (l < eps)return res;
	res.push_back(Line{ p,p + v2 });
	return res;
}

int max_n;
const int mn = 100000;
struct edge {
	int to, cap; ld cost; int rev;
};
typedef pair<ld, int> speP;
vector<edge> G[mn];
int par[mn];
ld dist[mn];
void add_edge(int from, int to, int cap, ld cost) {
	G[from].push_back({ to,cap,cost,(int)G[to].size() });
	G[to].push_back({ from,0,-cost,(int)G[from].size()-1 });
	max_n = max({ max_n,from + 1,to + 1 });
}
ld minimum_road(int s, int t) {
	fill(par, par + max_n, -1);
	fill(dist, dist + max_n, mod);
	dist[s] = 0;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,s });
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (id == t)continue;
		if (p.first > dist[id])continue;
		rep(j, G[id].size()) {
			if (G[id][j].cap > 0) {
				int to = G[id][j].to;
				ld nd = p.first + G[id][j].cost;
				if (nd < dist[to]) {
					dist[to] = nd;
					par[to] = id;
					q.push({ dist[to],to });
				}
			}
		}
	}
	int cur = t;
	while (cur != s) {
		int p = par[cur];
		if (p < 0)return -1;
		rep(j, G[p].size()) {
			if (G[p][j].cap > 0 && G[p][j].to == cur && dist[p] + G[p][j].cost == dist[cur]) {
				G[p][j].cap--;
				G[cur][G[p][j].rev].cap++;
				break;
			}
		}
		cur = p;
	}
	return dist[t];
}
ld minimum_cost_flow(int s, int t, int k) {
	ld ret = 0;
	rep(i, k) {
		ld z = minimum_road(s, t);
		if (z < 0)return -1;
		ret += z;
	}
	return ret;
}

bool isis_cs(Circle c, Line s) {
	ld dist = dist_sp(s,c.p);
	return dist < c.r - eps;
}

vector<Circle> c;

void solve() {
	int n; cin >> n;
	c.resize(2);
	rep(i, 2) {
		ld x, y, r; cin >> x >> y >> r;
		c[i] = { {x,y},r };
	}
	vector<Point> a(n), b(n);
	rep(i, n) {
		ld x, y; cin >> x >> y;
		a[i] = { x,y };
	}
	rep(i, n) {
		ld x, y; cin >> x >> y;
		b[i] = { x,y };
	}
	int s = 2 * n, t = 2 * n + 1;
	rep(i, n) {
		add_edge(s, i, 1, 0);
		add_edge(i + n,t, 1, 0);
	}
	vector<vector<Line>> l(n), r(n);
	rep(i, n) {
		rep(j, 2) {
			vector<Line> u = tangent_cp(c[j], a[i]);
			rep(k, u.size())l[i].push_back(u[k]);
			u = tangent_cp(c[j], b[i]);
			rep(k, u.size())r[i].push_back(u[k]);
		}
	}
	rep(i, n) {
		rep(j, n) {
			Point le = a[i], ri = b[j];
			ld cost = mod;
			{
				Line l = { le,ri };
				bool f = true;
				rep(k, 2) {
					if (isis_cs(c[k], l))f = false;
				}
				if (f) {
					cost = abs(ri - le);
					add_edge(i, n + j, 1, cost);
					continue;
				}
			}
			rep(k1, l[i].size()) {
				rep(k2,r[j].size()) {
					Line lle = l[i][k1];
					Line rri = r[j][k2];
					if (!isis_ll(lle, rri))continue;
					Point cn = is_ll(lle, rri);
					Line sl = { le,cn };
					Line sr = { ri,cn };
					bool valid = true;
					rep(k, 2) {
						if (isis_cs(c[k], sl) || isis_cs(c[k], sr)) {
							valid = false; break;
						}
					}
					if (valid) {
						cost = min(cost, abs(cn - le) + abs(cn - ri));
					}
				}
			}
			if (cost == mod)continue;
			add_edge(i, n + j, 1, cost);
		}
	}
	ld ans = minimum_cost_flow(s, t, n);
	if (ans == -1||ans>10000+eps) {
		cout << "Impossible" << endl;
	}
	else {
		cout << ans << endl;
	}
}


signed main() {
	cout << fixed << setprecision(10);
	solve();
	//stop
		return 0;
}
accuracy: 0.21875
time_ms: 120
memory_kb: 6804
final_rank: 13

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<utility>
#include<map>
#include<complex>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
typedef pair<ll, ll> LP;
typedef vector<int> vec;
#define rep(i,n) for(int i=0;i<n;i++)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define stop char nyaa;cin>>nyaa;
#define per(i,n) for(int i=n-1;i>=0;i--)

//geometry
typedef long double ld;
typedef complex<ld> Point;
const ld pi = acos(-1.0);
const ld eps = 1e-10;

bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
ld dot(Point a, Point b) { return real(conj(a)*b); }
ld cross(Point a, Point b) { return imag(conj(a)*b); }

struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}

Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a;
	Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

vector<Line> tangent_cp(Circle c, Point p) {
	vector<Line> res;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r*c.r);
	if (isnan(l))return res;
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	res.push_back(Line{ p,p + v1 });
	if (l < eps)return res;
	res.push_back(Line{ p,p + v2 });
	return res;
}

int max_n;
const int mn = 100000;
struct edge {
	int to, cap; ld cost; int rev;
};
typedef pair<ld, int> speP;
vector<edge> G[mn];
int par[mn];
ld dist[mn];
void add_edge(int from, int to, int cap, ld cost) {
	G[from].push_back({ to,cap,cost,(int)G[to].size() });
	G[to].push_back({ from,0,-cost,(int)G[from].size()-1 });
	max_n = max({ max_n,from + 1,to + 1 });
}
ld minimum_road(int s, int t) {
	fill(par, par + max_n, -1);
	fill(dist, dist + max_n, mod);
	dist[s] = 0;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,s });
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (id == t)continue;
		if (p.first > dist[id])continue;
		rep(j, G[id].size()) {
			if (G[id][j].cap > 0) {
				int to = G[id][j].to;
				ld nd = p.first + G[id][j].cost;
				if (nd < dist[to]) {
					dist[to] = nd;
					par[to] = id;
					q.push({ dist[to],to });
				}
			}
		}
	}
	int cur = t;
	while (cur != s) {
		int p = par[cur];
		if (p < 0)return -1;
		rep(j, G[p].size()) {
			if (G[p][j].cap > 0 && G[p][j].to == cur && dist[p] + G[p][j].cost == dist[cur]) {
				G[p][j].cap--;
				G[cur][G[p][j].rev].cap++;
				break;
			}
		}
		cur = p;
	}
	return dist[t];
}
ld minimum_cost_flow(int s, int t, int k) {
	ld ret = 0;
	rep(i, k) {
		ld z = minimum_road(s, t);
		if (z < 0)return -1;
		ret += z;
	}
	return ret;
}

bool isis_cs(Circle c, Line s) {
	ld dist = dist_sp(s,c.p);
	return dist < c.r - eps;
}

vector<Circle> c;

void solve() {
	int n; cin >> n;
	c.resize(2);
	rep(i, 2) {
		ld x, y, r; cin >> x >> y >> r;
		c[i] = { {x,y},r };
	}
	vector<Point> a(n), b(n);
	rep(i, n) {
		ld x, y; cin >> x >> y;
		a[i] = { x,y };
	}
	rep(i, n) {
		ld x, y; cin >> x >> y;
		b[i] = { x,y };
	}
	int s = 2 * n, t = 2 * n + 1;
	rep(i, n) {
		add_edge(s, i, 1, 0);
		add_edge(i + n,t, 1, 0);
	}
	vector<vector<Line>> l(n), r(n);
	rep(i, n) {
		rep(j, 2) {
			vector<Line> u = tangent_cp(c[j], a[i]);
			rep(k, u.size())l[i].push_back(u[k]);
			u = tangent_cp(c[j], b[i]);
			rep(k, u.size())r[i].push_back(u[k]);
		}
	}
	rep(i, n) {
		rep(j, n) {
			Point le = a[i], ri = b[j];
			ld cost = mod;
			{
				Line l = { le,ri };
				bool f = true;
				rep(k, 2) {
					if (isis_cs(c[k], l))f = false;
				}
				if (f) {
					cost = abs(ri - le);
					add_edge(i, n + j, 1, cost);
					continue;
				}
			}
			rep(k1, l[i].size()) {
				rep(k2,r[j].size()) {
					Line lle = l[i][k1];
					Line rri = r[j][k2];
					if (!isis_ll(lle, rri))continue;
					Point cn = is_ll(lle, rri);
					Line sl = { le,cn };
					Line sr = { ri,cn };
					bool valid = true;
					rep(k, 2) {
						if (isis_cs(c[k], sl) || isis_cs(c[k], sr)) {
							valid = false; break;
						}
					}
					if (valid) {
						cost = min(cost, abs(cn - le) + abs(cn - ri));
					}
				}
			}
			if (cost == mod)continue;
			add_edge(i, n + j, 1, cost);
		}
	}
	ld ans = minimum_cost_flow(s, t, n);
	if (ans == -1||ans>10000+eps) {
		cout << "Impossible" << endl;
	}
	else {
		cout << ans << endl;
	}
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	solve();
	//stop
		return 0;
}
accuracy: 0.21875
time_ms: 120
memory_kb: 6908
final_rank: 18

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<utility>
#include<map>
#include<complex>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
typedef pair<ll, ll> LP;
typedef vector<int> vec;
#define rep(i,n) for(int i=0;i<n;i++)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define stop char nyaa;cin>>nyaa;
#define per(i,n) for(int i=n-1;i>=0;i--)

//geometry
typedef long double ld;
typedef complex<ld> Point;
const ld pi = acos(-1.0);
const ld eps = 1e-8;

bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
ld dot(Point a, Point b) { return real(conj(a)*b); }
ld cross(Point a, Point b) { return imag(conj(a)*b); }

struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}

Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a;
	Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

vector<Line> tangent_cp(Circle c, Point p) {
	vector<Line> res;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r*c.r);
	if (isnan(l))return res;
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	res.push_back(Line{ p,p + v1 });
	if (l < eps)return res;
	res.push_back(Line{ p,p + v2 });
	return res;
}

int max_n;
const int mn = 100000;
struct edge {
	int to, cap; ld cost; int rev;
};
typedef pair<ld, int> speP;
vector<edge> G[mn];
P par[mn];
ld dist[mn];
void add_edge(int from, int to, int cap, ld cost) {
	G[from].push_back({ to,cap,cost,(int)G[to].size() });
	G[to].push_back({ from,0,-cost,(int)G[from].size() - 1 });
	max_n = max({ max_n,from + 1,to + 1 });
}
ld minimum_road(int s, int t) {
	fill(par, par + max_n, P{ -1,-1 });
	fill(dist, dist + max_n, mod);
	dist[s] = 0;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,s });
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (id == t)continue;
		if (p.first > dist[id])continue;
		rep(j, G[id].size()) {
			if (G[id][j].cap > 0) {
				int to = G[id][j].to;
				ld nd = p.first + G[id][j].cost;
				if (nd < dist[to]) {
					dist[to] = nd;
					par[to] = { id,j };
					q.push({ dist[to],to });
				}
			}
		}
	}
	int cur = t;
	while (cur != s) {
		int p = par[cur].first,j=par[cur].second;
		if (p < 0)return -1;
		edge &e = G[p][j];
		e.cap--;
		G[e.to][e.rev].cap++;
		cur = p;
	}
	return dist[t];
}
ld minimum_cost_flow(int s, int t, int k) {
	ld ret = 0;
	rep(i, k) {
		ld z = minimum_road(s, t);
		if (z < 0)return -1;
		ret += z;
	}
	return ret;
}

bool isis_cs(Circle c, Line s) {
	ld dist = dist_sp(s, c.p);
	return dist < c.r - eps;
}


void solve() {
	int n; cin >> n;
	vector<Circle> c(2);
	rep(i, 2) {
		ld x, y, r; cin >> x >> y >> r;
		c[i] = { { x,y },r };
	}
	vector<Point> a(n), b(n);
	rep(i, n) {
		ld x, y; cin >> x >> y;
		a[i] = { x,y };
	}
	rep(i, n) {
		ld x, y; cin >> x >> y;
		b[i] = { x,y };
	}
	int s = 2 * n, t = 2 * n + 1;
	rep(i, n) {
		add_edge(s, i, 1, 0);
		add_edge(i + n, t, 1, 0);
	}
	vector<vector<Line>> l(n), r(n);
	rep(i, n) {
		rep(j, 2) {
			vector<Line> u = tangent_cp(c[j], a[i]);
			rep(k, u.size())l[i].push_back(u[k]);
			u = tangent_cp(c[j], b[i]);
			rep(k, u.size())r[i].push_back(u[k]);
		}
	}
	rep(i, n) {
		rep(j, n) {
			Point le = a[i], ri = b[j];
			ld cost = mod;
			{
				Line l = { le,ri };
				bool f = true;
				rep(k, 2) {
					if (isis_cs(c[k], l))f = false;
				}
				if (f) {
					cost = abs(ri - le);
					add_edge(i, n + j, 1, cost);
					continue;
				}
			}
			rep(k1, l[i].size()) {
				rep(k2, r[j].size()) {
					Line lle = l[i][k1];
					Line rri = r[j][k2];
					if (!isis_ll(lle, rri))continue;
					Point cn = is_ll(lle, rri);
					Line sl = { le,cn };
					Line sr = { ri,cn };
					bool valid = true;
					rep(k, 2) {
						if (isis_cs(c[k], sl) || isis_cs(c[k], sr)) {
							valid = false; break;
						}
					}
					if (valid) {
						cost = min(cost, abs(cn - le) + abs(cn - ri));
					}
				}
			}
			if (cost == mod||cost>10000+eps)continue;
			add_edge(i, n + j, 1, cost);
		}
	}
	ld ans = minimum_cost_flow(s, t, n);
	if (10000 < ans&&ans < 10000 + eps)ans = 10000;
	if (ans == -1 || ans>10000 + eps) {
		cout << "Impossible" << endl;
	}
	else {
		cout << ans << endl;
	}
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	solve();
	//stop
	return 0;
}
accuracy: 0.21875
time_ms: 120
memory_kb: 6872
final_rank: 16

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<utility>
#include<map>
#include<complex>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
typedef pair<ll, ll> LP;
typedef vector<int> vec;
#define rep(i,n) for(int i=0;i<n;i++)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define stop char nyaa;cin>>nyaa;
#define per(i,n) for(int i=n-1;i>=0;i--)

//geometry
typedef long double ld;
typedef complex<ld> Point;
const ld pi = acos(-1.0);
const ld eps = 1e-8;

bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
ld dot(Point a, Point b) { return real(conj(a)*b); }
ld cross(Point a, Point b) { return imag(conj(a)*b); }

struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}

Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a;
	Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

vector<Line> tangent_cp(Circle c, Point p) {
	vector<Line> res;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r*c.r);
	if (isnan(l))return res;
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	res.push_back(Line{ p,p + v1 });
	if (l < eps)return res;
	res.push_back(Line{ p,p + v2 });
	return res;
}

int max_n;
const int mn = 100000;
struct edge {
	int to, cap; ld cost; int rev;
};
typedef pair<ld, int> speP;
vector<edge> G[mn];
P par[mn];
ld dist[mn];
void add_edge(int from, int to, int cap, ld cost) {
	G[from].push_back({ to,cap,cost,(int)G[to].size() });
	G[to].push_back({ from,0,-cost,(int)G[from].size() - 1 });
	max_n = max({ max_n,from + 1,to + 1 });
}
ld minimum_road(int s, int t) {
	fill(par, par + max_n, P{ -1,-1 });
	fill(dist, dist + max_n, mod);
	dist[s] = 0;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,s });
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (id == t)continue;
		if (p.first > dist[id])continue;
		rep(j, G[id].size()) {
			if (G[id][j].cap > 0) {
				int to = G[id][j].to;
				ld nd = p.first + G[id][j].cost;
				if (nd < dist[to]) {
					dist[to] = nd;
					par[to] = { id,j };
					q.push({ dist[to],to });
				}
			}
		}
	}
	int cur = t;
	while (cur != s) {
		int p = par[cur].first,j=par[cur].second;
		if (p < 0)return -1;
		edge &e = G[p][j];
		e.cap--;
		G[e.to][e.rev].cap++;
		cur = p;
	}
	return dist[t];
}
ld minimum_cost_flow(int s, int t, int k) {
	ld ret = 0;
	rep(i, k) {
		ld z = minimum_road(s, t);
		if (z < 0)return -1;
		ret += z;
	}
	return ret;
}

bool isis_cs(Circle c, Line s) {
	ld dist = dist_sp(s, c.p);
	return dist < c.r - eps;
}

vector<Circle> c;

void solve() {
	int n; cin >> n;
	c.resize(2);
	rep(i, 2) {
		ld x, y, r; cin >> x >> y >> r;
		c[i] = { { x,y },r };
	}
	vector<Point> a(n), b(n);
	rep(i, n) {
		ld x, y; cin >> x >> y;
		a[i] = { x,y };
	}
	rep(i, n) {
		ld x, y; cin >> x >> y;
		b[i] = { x,y };
	}
	int s = 2 * n, t = 2 * n + 1;
	rep(i, n) {
		add_edge(s, i, 1, 0);
		add_edge(i + n, t, 1, 0);
	}
	vector<vector<Line>> l(n), r(n);
	rep(i, n) {
		rep(j, 2) {
			vector<Line> u = tangent_cp(c[j], a[i]);
			rep(k, u.size())l[i].push_back(u[k]);
			u = tangent_cp(c[j], b[i]);
			rep(k, u.size())r[i].push_back(u[k]);
		}
	}
	rep(i, n) {
		rep(j, n) {
			Point le = a[i], ri = b[j];
			ld cost = mod;
			{
				Line l = { le,ri };
				bool f = true;
				rep(k, 2) {
					if (isis_cs(c[k], l))f = false;
				}
				if (f) {
					cost = abs(ri - le);
					add_edge(i, n + j, 1, cost);
					continue;
				}
			}
			rep(k1, l[i].size()) {
				rep(k2, r[j].size()) {
					Line lle = l[i][k1];
					Line rri = r[j][k2];
					if (!isis_ll(lle, rri))continue;
					Point cn = is_ll(lle, rri);
					Line sl = { le,cn };
					Line sr = { ri,cn };
					bool valid = true;
					rep(k, 2) {
						if (isis_cs(c[k], sl) || isis_cs(c[k], sr)) {
							valid = false; break;
						}
					}
					if (valid) {
						cost = min(cost, abs(cn - le) + abs(cn - ri));
					}
				}
			}
			if (cost == mod)continue;
			add_edge(i, n + j, 1, cost);
		}
	}
	ld ans = minimum_cost_flow(s, t, n);
	if (ans == -1 || ans>10000 + eps) {
		cout << "Impossible" << endl;
	}
	else {
		cout << ans << endl;
	}
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	solve();
	//stop
	return 0;
}
accuracy: 0.21875
time_ms: 120
memory_kb: 6928
final_rank: 19

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<utility>
#include<map>
#include<complex>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
typedef pair<ll, ll> LP;
typedef vector<int> vec;
#define rep(i,n) for(int i=0;i<n;i++)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define stop char nyaa;cin>>nyaa;
#define per(i,n) for(int i=n-1;i>=0;i--)

//geometry
typedef long double ld;
typedef complex<ld> Point;
const ld pi = acos(-1.0);
const ld eps = 1e-8;

bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
ld dot(Point a, Point b) { return real(conj(a)*b); }
ld cross(Point a, Point b) { return imag(conj(a)*b); }

struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}

Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a;
	Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

vector<Line> tangent_cp(Circle c, Point p) {
	vector<Line> res;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r*c.r);
	if (isnan(l))return res;
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	res.push_back(Line{ p,p + v1 });
	if (l < eps)return res;
	res.push_back(Line{ p,p + v2 });
	return res;
}

int max_n;
const int mn = 100000;
struct edge {
	int to, cap; ld cost; int rev;
};
typedef pair<ld, int> speP;
vector<edge> G[mn];
P par[mn];
ld dist[mn];
void add_edge(int from, int to, int cap, ld cost) {
	G[from].push_back({ to,cap,cost,(int)G[to].size() });
	G[to].push_back({ from,0,-cost,(int)G[from].size() - 1 });
	max_n = max({ max_n,from + 1,to + 1 });
}
ld minimum_road(int s, int t) {
	fill(par, par + max_n, P{ -1,-1 });
	fill(dist, dist + max_n, mod);
	dist[s] = 0;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,s });
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (id == t)continue;
		if (p.first > dist[id])continue;
		rep(j, G[id].size()) {
			if (G[id][j].cap > 0) {
				int to = G[id][j].to;
				ld nd = p.first + G[id][j].cost;
				if (nd < dist[to]) {
					dist[to] = nd;
					par[to] = { id,j };
					q.push({ dist[to],to });
				}
			}
		}
	}
	int cur = t;
	while (cur != s) {
		int p = par[cur].first,j=par[cur].second;
		if (p < 0)return -1;
		edge &e = G[p][j];
		e.cap--;
		G[e.to][e.rev].cap++;
		cur = p;
	}
	return dist[t];
}
ld minimum_cost_flow(int s, int t, int k) {
	ld ret = 0;
	rep(i, k) {
		ld z = minimum_road(s, t);
		if (z < 0)return -1;
		ret += z;
	}
	return ret;
}

bool isis_cs(Circle c, Line s) {
	ld dist = dist_sp(s, c.p);
	return dist < c.r - eps;
}

vector<Circle> c;

void solve() {
	int n; cin >> n;
	c.resize(2);
	rep(i, 2) {
		ld x, y, r; cin >> x >> y >> r;
		c[i] = { { x,y },r };
	}
	vector<Point> a(n), b(n);
	rep(i, n) {
		ld x, y; cin >> x >> y;
		a[i] = { x,y };
	}
	rep(i, n) {
		ld x, y; cin >> x >> y;
		b[i] = { x,y };
	}
	int s = 2 * n, t = 2 * n + 1;
	rep(i, n) {
		add_edge(s, i, 1, 0);
		add_edge(i + n, t, 1, 0);
	}
	vector<vector<Line>> l(n), r(n);
	rep(i, n) {
		rep(j, 2) {
			vector<Line> u = tangent_cp(c[j], a[i]);
			rep(k, u.size())l[i].push_back(u[k]);
			u = tangent_cp(c[j], b[i]);
			rep(k, u.size())r[i].push_back(u[k]);
		}
	}
	rep(i, n) {
		rep(j, n) {
			Point le = a[i], ri = b[j];
			ld cost = mod;
			{
				Line l = { le,ri };
				bool f = true;
				rep(k, 2) {
					if (isis_cs(c[k], l))f = false;
				}
				if (f) {
					cost = abs(ri - le);
					add_edge(i, n + j, 1, cost);
					continue;
				}
			}
			rep(k1, l[i].size()) {
				rep(k2, r[j].size()) {
					Line lle = l[i][k1];
					Line rri = r[j][k2];
					if (!isis_ll(lle, rri))continue;
					Point cn = is_ll(lle, rri);
					Line sl = { le,cn };
					Line sr = { ri,cn };
					bool valid = true;
					rep(k, 2) {
						if (isis_cs(c[k], sl) || isis_cs(c[k], sr)) {
							valid = false; break;
						}
					}
					if (valid) {
						cost = min(cost, abs(cn - le) + abs(cn - ri));
					}
				}
			}
			if (cost == mod)continue;
			add_edge(i, n + j, 1, cost);
		}
	}
	ld ans = minimum_cost_flow(s, t, n);
	if (ans == -1 || ans>10000 + eps) {
		cout << "Impossible" << endl;
	}
	else {
		cout << ans << endl;
	}
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	solve();
	//stop
	return 0;
}
accuracy: 0.21875
time_ms: 120
memory_kb: 6840
final_rank: 14

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<utility>
#include<map>
#include<complex>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
typedef pair<ll, ll> LP;
typedef vector<int> vec;
#define rep(i,n) for(int i=0;i<n;i++)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define stop char nyaa;cin>>nyaa;
#define per(i,n) for(int i=n-1;i>=0;i--)

//geometry
typedef long double ld;
typedef complex<ld> Point;
const ld pi = acos(-1.0);
const ld eps = 1e-6;

bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
ld dot(Point a, Point b) { return real(conj(a)*b); }
ld cross(Point a, Point b) { return imag(conj(a)*b); }

struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}

Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a;
	Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

vector<Line> tangent_cp(Circle c, Point p) {
	vector<Line> res;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r*c.r);
	if (isnan(l))return res;
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	res.push_back(Line{ p,p + v1 });
	if (l < eps)return res;
	res.push_back(Line{ p,p + v2 });
	return res;
}

int max_n;
const int mn = 100000;
struct edge {
	int to, cap; ld cost; int rev;
};
typedef pair<ld, int> speP;
vector<edge> G[mn];
int par[mn];
ld dist[mn];
void add_edge(int from, int to, int cap, ld cost) {
	G[from].push_back({ to,cap,cost,(int)G[to].size() });
	G[to].push_back({ from,0,-cost,(int)G[from].size() - 1 });
	max_n = max({ max_n,from + 1,to + 1 });
}
ld minimum_road(int s, int t) {
	fill(par, par + max_n, -1);
	fill(dist, dist + max_n, mod);
	dist[s] = 0;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,s });
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (id == t)continue;
		if (p.first > dist[id])continue;
		rep(j, G[id].size()) {
			if (G[id][j].cap > 0) {
				int to = G[id][j].to;
				ld nd = p.first + G[id][j].cost;
				if (nd < dist[to]) {
					dist[to] = nd;
					par[to] = id;
					q.push({ dist[to],to });
				}
			}
		}
	}
	int cur = t;
	while (cur != s) {
		int p = par[cur];
		if (p < 0)return -1;
		rep(j, G[p].size()) {
			if (G[p][j].cap > 0 && G[p][j].to == cur && eq(dist[p] + G[p][j].cost,dist[cur])) {
				G[p][j].cap--;
				G[cur][G[p][j].rev].cap++;
				break;
			}
		}
		cur = p;
	}
	return dist[t];
}
ld minimum_cost_flow(int s, int t, int k) {
	ld ret = 0;
	rep(i, k) {
		ld z = minimum_road(s, t);
		if (z < 0)return -1;
		ret += z;
	}
	return ret;
}

bool isis_cs(Circle c, Line s) {
	ld dist = dist_sp(s, c.p);
	return dist < c.r - eps;
}

vector<Circle> c;

void solve() {
	int n; cin >> n;
	c.resize(2);
	rep(i, 2) {
		ld x, y, r; cin >> x >> y >> r;
		c[i] = { { x,y },r };
	}
	vector<Point> a(n), b(n);
	rep(i, n) {
		ld x, y; cin >> x >> y;
		a[i] = { x,y };
	}
	rep(i, n) {
		ld x, y; cin >> x >> y;
		b[i] = { x,y };
	}
	int s = 2 * n, t = 2 * n + 1;
	rep(i, n) {
		add_edge(s, i, 1, 0);
		add_edge(i + n, t, 1, 0);
	}
	vector<vector<Line>> l(n), r(n);
	rep(i, n) {
		rep(j, 2) {
			vector<Line> u = tangent_cp(c[j], a[i]);
			rep(k, u.size())l[i].push_back(u[k]);
			u = tangent_cp(c[j], b[i]);
			rep(k, u.size())r[i].push_back(u[k]);
		}
	}
	rep(i, n) {
		rep(j, n) {
			Point le = a[i], ri = b[j];
			ld cost = mod;
			{
				Line l = { le,ri };
				bool f = true;
				rep(k, 2) {
					if (isis_cs(c[k], l))f = false;
				}
				if (f) {
					cost = abs(ri - le);
					add_edge(i, n + j, 1, cost);
					continue;
				}
			}
			rep(k1, l[i].size()) {
				rep(k2, r[j].size()) {
					Line lle = l[i][k1];
					Line rri = r[j][k2];
					if (!isis_ll(lle, rri))continue;
					Point cn = is_ll(lle, rri);
					Line sl = { le,cn };
					Line sr = { ri,cn };
					bool valid = true;
					rep(k, 2) {
						if (isis_cs(c[k], sl) || isis_cs(c[k], sr)) {
							valid = false; break;
						}
					}
					if (valid) {
						cost = min(cost, abs(cn - le) + abs(cn - ri));
					}
				}
			}
			if (cost == mod)continue;
			add_edge(i, n + j, 1, cost);
		}
	}
	ld ans = minimum_cost_flow(s, t, n);
	if (ans == -1 || ans>10000 + eps) {
		cout << "Impossible" << endl;
	}
	else {
		cout << ans << endl;
	}
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	solve();
	//stop
	return 0;
}
accuracy: 0.21875
time_ms: 120
memory_kb: 6892
final_rank: 17

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<utility>
#include<map>
#include<complex>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
typedef pair<ll, ll> LP;
typedef vector<int> vec;
#define rep(i,n) for(int i=0;i<n;i++)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define stop char nyaa;cin>>nyaa;
#define per(i,n) for(int i=n-1;i>=0;i--)

//geometry
typedef long double ld;
typedef complex<ld> Point;
const ld pi = acos(-1.0);
const ld eps = 1e-5;

bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
ld dot(Point a, Point b) { return real(conj(a)*b); }
ld cross(Point a, Point b) { return imag(conj(a)*b); }

struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}

Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a;
	Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

vector<Line> tangent_cp(Circle c, Point p) {
	vector<Line> res;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r*c.r);
	if (isnan(l))return res;
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	res.push_back(Line{ p,p + v1 });
	if (l < eps)return res;
	res.push_back(Line{ p,p + v2 });
	return res;
}

int max_n;
const int mn = 100000;
struct edge {
	int to, cap; ld cost; int rev;
};
typedef pair<ld, int> speP;
vector<edge> G[mn];
int par[mn];
ld dist[mn];
void add_edge(int from, int to, int cap, ld cost) {
	G[from].push_back({ to,cap,cost,(int)G[to].size() });
	G[to].push_back({ from,0,-cost,(int)G[from].size() - 1 });
	max_n = max({ max_n,from + 1,to + 1 });
}
ld minimum_road(int s, int t) {
	fill(par, par + max_n, -1);
	fill(dist, dist + max_n, mod);
	dist[s] = 0;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,s });
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (id == t)continue;
		if (p.first > dist[id])continue;
		rep(j, G[id].size()) {
			if (G[id][j].cap > 0) {
				int to = G[id][j].to;
				ld nd = p.first + G[id][j].cost;
				if (nd < dist[to]) {
					dist[to] = nd;
					par[to] = id;
					q.push({ dist[to],to });
				}
			}
		}
	}
	int cur = t;
	while (cur != s) {
		int p = par[cur];
		if (p < 0)return -1;
		rep(j, G[p].size()) {
			if (G[p][j].cap > 0 && G[p][j].to == cur && dist[p] + G[p][j].cost == dist[cur]) {
				G[p][j].cap--;
				G[cur][G[p][j].rev].cap++;
				break;
			}
		}
		cur = p;
	}
	return dist[t];
}
ld minimum_cost_flow(int s, int t, int k) {
	ld ret = 0;
	rep(i, k) {
		ld z = minimum_road(s, t);
		if (z < 0)return -1;
		ret += z;
	}
	return ret;
}

bool isis_cs(Circle c, Line s) {
	ld dist = dist_sp(s, c.p);
	return dist < c.r - eps;
}

vector<Circle> c;

void solve() {
	int n; cin >> n;
	c.resize(2);
	rep(i, 2) {
		ld x, y, r; cin >> x >> y >> r;
		c[i] = { { x,y },r };
	}
	vector<Point> a(n), b(n);
	rep(i, n) {
		ld x, y; cin >> x >> y;
		a[i] = { x,y };
	}
	rep(i, n) {
		ld x, y; cin >> x >> y;
		b[i] = { x,y };
	}
	int s = 2 * n, t = 2 * n + 1;
	rep(i, n) {
		add_edge(s, i, 1, 0);
		add_edge(i + n, t, 1, 0);
	}
	vector<vector<Line>> l(n), r(n);
	rep(i, n) {
		rep(j, 2) {
			vector<Line> u = tangent_cp(c[j], a[i]);
			rep(k, u.size())l[i].push_back(u[k]);
			u = tangent_cp(c[j], b[i]);
			rep(k, u.size())r[i].push_back(u[k]);
		}
	}
	rep(i, n) {
		rep(j, n) {
			Point le = a[i], ri = b[j];
			ld cost = mod;
			{
				Line l = { le,ri };
				bool f = true;
				rep(k, 2) {
					if (isis_cs(c[k], l))f = false;
				}
				if (f) {
					cost = abs(ri - le);
					add_edge(i, n + j, 1, cost);
					continue;
				}
			}
			rep(k1, l[i].size()) {
				rep(k2, r[j].size()) {
					Line lle = l[i][k1];
					Line rri = r[j][k2];
					if (!isis_ll(lle, rri))continue;
					Point cn = is_ll(lle, rri);
					Line sl = { le,cn };
					Line sr = { ri,cn };
					bool valid = true;
					rep(k, 2) {
						if (isis_cs(c[k], sl) || isis_cs(c[k], sr)) {
							valid = false; break;
						}
					}
					if (valid) {
						cost = min(cost, abs(cn - le) + abs(cn - ri));
					}
				}
			}
			if (cost == mod)continue;
			add_edge(i, n + j, 1, cost);
		}
	}
	ld ans = minimum_cost_flow(s, t, n);
	if (ans == -1 || ans>10000 + eps) {
		cout << "Impossible" << endl;
	}
	else {
		cout << ans << endl;
	}
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	solve();
	//stop
	return 0;
}
accuracy: 0.21875
time_ms: 120
memory_kb: 6852
final_rank: 15

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<utility>
#include<map>
#include<complex>
using namespace std;
typedef long long ll;
const ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int> P;
typedef pair<ll, ll> LP;
typedef vector<int> vec;
#define rep(i,n) for(int i=0;i<n;i++)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define stop char nyaa;cin>>nyaa;
#define per(i,n) for(int i=n-1;i>=0;i--)

//geometry
typedef long double ld;
typedef complex<ld> Point;
const ld pi = acos(-1.0);
const ld eps = 1e-10;

bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
ld dot(Point a, Point b) { return real(conj(a)*b); }
ld cross(Point a, Point b) { return imag(conj(a)*b); }

struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
bool isis_sp(Line s, Point p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}
ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}
ld dist_sp(Line s, Point p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(p - r) : min(abs(p - s.a), abs(p - s.b));
}

Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a;
	Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

vector<Line> tangent_cp(Circle c, Point p) {
	vector<Line> res;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r*c.r);
	if (isnan(l))return res;
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	res.push_back(Line{ p,p + v1 });
	if (l < eps)return res;
	res.push_back(Line{ p,p + v2 });
	return res;
}

int max_n;
const int mn = 100000;
struct edge {
	int to, cap; ld cost; int rev;
};
typedef pair<ld, int> speP;
vector<edge> G[mn];
int par[mn];
ld dist[mn];
void add_edge(int from, int to, int cap, ld cost) {
	G[from].push_back({ to,cap,cost,(int)G[to].size() });
	G[to].push_back({ from,0,-cost,(int)G[from].size()-1 });
	max_n = max({ max_n,from + 1,to + 1 });
}
ld minimum_road(int s, int t) {
	fill(par, par + max_n, -1);
	fill(dist, dist + max_n, mod);
	dist[s] = 0;
	priority_queue<speP, vector<speP>, greater<speP>> q;
	q.push({ 0,s });
	while (!q.empty()) {
		speP p = q.top(); q.pop();
		int id = p.second;
		if (id == t)continue;
		if (p.first > dist[id])continue;
		rep(j, G[id].size()) {
			if (G[id][j].cap > 0) {
				int to = G[id][j].to;
				ld nd = p.first + G[id][j].cost;
				if (nd < dist[to]) {
					dist[to] = nd;
					par[to] = id;
					q.push({ dist[to],to });
				}
			}
		}
	}
	int cur = t;
	while (cur != s) {
		int p = par[cur];
		if (p < 0)return -1;
		rep(j, G[p].size()) {
			if (G[p][j].cap > 0 && G[p][j].to == cur && dist[p] + G[p][j].cost == dist[cur]) {
				G[p][j].cap--;
				G[cur][G[p][j].rev].cap++;
				break;
			}
		}
		cur = p;
	}
	return dist[t];
}
ld minimum_cost_flow(int s, int t, int k) {
	ld ret = 0;
	rep(i, k) {
		ld z = minimum_road(s, t);
		if (z < 0)return -1;
		ret += z;
	}
	return ret;
}

bool isis_cs(Circle c, Line s) {
	ld dist = dist_sp(s,c.p);
	return dist < c.r - eps;
}

vector<Circle> c;

void solve() {
	int n; cin >> n;
	c.resize(2);
	rep(i, 2) {
		ld x, y, r; cin >> x >> y >> r;
		c[i] = { {x,y},r };
	}
	vector<Point> a(n), b(n);
	rep(i, n) {
		ld x, y; cin >> x >> y;
		a[i] = { x,y };
	}
	rep(i, n) {
		ld x, y; cin >> x >> y;
		b[i] = { x,y };
	}
	int s = 2 * n, t = 2 * n + 1;
	rep(i, n) {
		add_edge(s, i, 1, 0);
		add_edge(i + n,t, 1, 0);
	}
	vector<vector<Line>> l(n), r(n);
	rep(i, n) {
		rep(j, 2) {
			vector<Line> u = tangent_cp(c[j], a[i]);
			rep(k, u.size())l[i].push_back(u[k]);
			u = tangent_cp(c[j], b[i]);
			rep(k, u.size())r[i].push_back(u[k]);
		}
	}
	rep(i, n) {
		rep(j, n) {
			Point le = a[i], ri = b[j];
			ld cost = mod;
			{
				Line l = { le,ri };
				bool f = true;
				rep(k, 2) {
					if (isis_cs(c[k], l))f = false;
				}
				if (f) {
					cost = abs(ri - le);
					add_edge(i, n + j, 1, cost);
					continue;
				}
			}
			rep(k1, l[i].size()) {
				rep(k2,r[j].size()) {
					Line lle = l[i][k1];
					Line rri = r[j][k2];
					if (!isis_ll(lle, rri))continue;
					Point cn = is_ll(lle, rri);
					Line sl = { le,cn };
					Line sr = { ri,cn };
					bool valid = true;
					rep(k, 2) {
						if (isis_cs(c[k], sl) || isis_cs(c[k], sr)) {
							valid = false; break;
						}
					}
					if (valid) {
						cost = min(cost, abs(cn - le) + abs(cn - ri));
					}
				}
			}
			if (cost == mod)continue;
			add_edge(i, n + j, 1, cost);
		}
	}
	ld ans = minimum_cost_flow(s, t, n);
	if (ans == -1||ans>10000+eps) {
		cout << "Impossible" << endl;
	}
	else {
		cout << ans << endl;
	}
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(10);
	solve();
	//stop
		return 0;
}
accuracy: 0.21875
time_ms: 120
memory_kb: 6928
final_rank: 19