Problem:
F - Polygon Guards
Problem Statement
You are an IT system administrator in the Ministry of Defense of Polygon Country.
Polygon Country's border forms the polygon with $N$ vertices. Drawn on the 2D-plane, all of its vertices are at the lattice points and all of its edges are parallel with either the $x$-axis or the $y$-axis.
In order to prevent enemies from invading the country, it is surrounded by very strong defense walls along its border. However, on the vertices, the junctions of walls have unavoidable structural weaknesses. Therefore, enemies might attack and invade from the vertices.
To observe the vertices and find an invasion by enemies as soon as possible, the ministry decided to hire some guards. The ministry plans to locate them on some vertices such that all the vertices are observed by at least one guard. A guard at the vertex $A$ can observe a vertex $B$ if the entire segment connecting $A$ and $B$ is inside or on the edge of Polygon Country. Of course, guards can observe the vertices they are located on. And a guard can observe  simultaneously all the vertices he or she can observe.
To reduce the defense expense, the ministry wants to minimize the number of guards. Your task is to calculate the minimum number of guards required to observe all the vertices of Polygon Country.
Input
The input is formatted as follows.
$N$
$X_1$ $Y_1$
:
:
$X_N$ $Y_N$
The first line contains an even integer $N$ ($4 \le N \lt 40$). The following $N$ lines describe the vertices of Polygon Country. Each of the lines contains two integers, $X_i$ and $Y_i$ ($1 \le i \le N$, $\lvert X_i \rvert \le 1{,}000$, $\lvert Y_i \rvert \le 1{,}000$), separated by one space. The position of the $i$-th vertex is $(X_i,Y_i)$.
If $i$ is odd, $X_i = X_{i+1}$, $Y_i \ne Y_{i+1}$. Otherwise, $X_i \ne X_{i+1}$, $Y_i = Y_{i+1}$. Here, we regard that $X_{N+1} = X_1$, and $Y_{N+1} = Y_1$. The vertices are given in counterclockwise order under the coordinate system that the $x$-axis goes right, and the $y$-axis goes up. The shape of Polygon Country is simple. That is, each edge doesn’t share any points with other edges except that its both end points are shared with its neighbor edges.
Output
Print the minimum number of guards in one line.
Sample Input 1
8
0 2
0 0
2 0
2 1
3 1
3 3
1 3
1 2
Output for the Sample Input 1
1
Sample Input 2
12
0 0
0 -13
3 -13
3 -10
10 -10
10 10
-1 10
-1 13
-4 13
-4 10
-10 10
-10 0
Output for the Sample Input 2
2

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
using namespace std;
const int maxp=50;
const double eps=1e-8;
int n;
inline int sgn(double v)
{
	if(abs(v)<eps)return 0;
	return v<0?-1:1;
}
struct Point
{
	double x,y;
	Point(double X=0,double Y=0)
	{
		x=X,y=Y;
	}
	double operator *(const Point &p)
	{
		return x*p.x+y*p.y;
	}
	double operator ^(const Point &p)
	{
		return x*p.y-y*p.x;
	}
	Point operator -(const Point &p)
	{
		return Point(x-p.x,y-p.y);
	}
	Point operator +(const Point &p)
	{
		return Point(x+p.x,y+p.y);
	}
	Point operator *(const double &c)
	{
		return Point(x*c,y*c);
	}
	Point operator /(const double &c)
	{
		return Point(x/c,y/c);
	}
	bool operator <(const Point &p)const
	{
		if(sgn(x-p.x))return x<p.x;
		else return y<p.y;
	}
}pt[maxp];
struct Segment
{
	Point st,ed;
	Segment(){}
	Segment(Point s,Point d)
	{
		st=s;ed=d;
	}
};
bool see[maxp][maxp];
Point Insect(Segment &p,Segment &q)
{
	double u=(p.ed-p.st)^(q.st-p.st),v=(p.st-p.ed)^(q.ed-p.st);
	return Point((q.st*v+q.ed*u)/(u+v));
}
bool inpoly(Point p)
{
	int con=0;
	Segment now,tmp;
	Point cp;
	now.st=p;
	now.ed=Point(p.x+27051995,p.y+19952705);
	for(int i=0;i<n;++i)
	{
		tmp=Segment(pt[i],pt[(i+1)%n]);
		if(sgn( (tmp.ed-p)^(p-tmp.st) ) == 0)
		{
			if(sgn( (p-tmp.ed)*(p-tmp.st) ) <= 0 )return true;
		}
		if(sgn( (tmp.ed-tmp.st)^(now.ed-now.st) ) )
		{
			cp=Insect(now,tmp);
			if(sgn( (tmp.ed-cp)*(cp-tmp.st) )>0 && sgn( (now.ed-cp)*(cp-now.st) ) >0)
				++con;
		}
	}
	return con%2;
}
bool judge(int u,int v)
{
	vector<Point> cpt({pt[u]});
	Segment cur(pt[u],pt[v]);
	//cout <<u<<" u&v "<<v<<" "<<cpt.size()<<endl;
	int con=0;
	for(int i=0;i<n;++i)
	{
		Segment ply(pt[i],pt[(i+1)%n]);
		if( sgn( (cur.ed-cur.st)^(ply.ed-ply.st) )==0)continue;
		Point cp=Insect(cur,ply);
		if( sgn( (cp-cur.st)*(cp-cur.ed) ) <=0 
			&& sgn( (cp-ply.st)*(cp-ply.ed) ) <=0)
			cpt.push_back(cp);
	}
	//cout <<"cal crosspoint"<<endl;
	cpt.push_back(pt[v]);
	sort(cpt.begin(),cpt.end());
	//cout <<"sorted crosspoint"<<endl;
	for(int i=1;i<cpt.size();++i)
		if(!inpoly( (cpt[i-1]+cpt[i])/2 ))return false;
	return true;
}
void getsee(int u)
{
	for(int i=0;i<n;++i)
		if(i==u)see[u][i]=true;
		else
			see[u][i]=judge(u,i);
}
const int maxn=50;
const int maxm=50;
const int maxv=maxn*maxm;
struct DLX
{
	int n,m,sz;
	int L[maxv],R[maxv],U[maxv],D[maxv],Row[maxv],Col[maxv];
	int H[maxn],S[maxm];
	int ansd;
	void init(int N,int M)
	{
		n=N;m=M;
		for(int i=0;i<=m;++i)
		{
			S[i]=0;
			U[i]=D[i]=i;
			L[i]=(i+m)%(m+1);
			R[i]=(i+1)%(m+1);
		}
		sz=m;
		for(int i=1;i<=n;++i)H[i]=-1;
	}
	void Link(int r,int c)
	{
		++S[Col[++sz]=c];
		Row[sz]=r;
		D[sz]=D[c];U[D[c]]=sz;
		U[sz]=c;D[c]=sz;
		if(H[r]<0)H[r]=L[sz]=R[sz]=sz;
		else
		{
			R[sz]=R[H[r]];
			L[R[H[r]]]=sz;
			L[sz]=H[r];
			R[H[r]]=sz;
		}
	}
	void remove(int c)
	{
		for(int i=D[c];i!=c;i=D[i])
			L[R[i]]=L[i],R[L[i]]=R[i];
	}
	void resume(int c)
	{
		for(int i=U[c];i!=c;i=U[i])
			L[R[i]]=R[L[i]]=i;
	}
	bool v[maxm];
	int p()
	{
		int res=0;
		for(int c=R[0];c!=0;c=R[c])v[c]=false;
		for(int c=R[0];c!=0;c=R[c])
			if(!v[c])
			{
				++res;
				v[c]=true;
				for(int i=D[c];i!=c;i=D[i])
					for(int j=R[i];j!=i;j=R[j])
						v[Col[j]]=true;
			}
		return res;
	}
	vector<int> path;
	void Dance(int d)
	{
		if(d+p()>ansd)return;
		if(R[0]==0)
		{
			//if(d<ansd){cout <<"choes:"<<" ans:"<<ansd<<" "<<path.size()<<endl;for(int v=0;v<path.size();++v){cout <<path[v]<<":";for(int i=0;i<n;++i)cout <<see[path[v]-1][i]<<" ";cout <<endl;}}
			ansd=min(ansd,d);
			return;
		}
		int c=R[0];
		for(int i=R[0];i!=0;i=R[i])
			if(S[i]<S[c])c=i;
		for(int i=D[c];i!=c;i=D[i])
		{
			path.push_back(Row[i]);
			remove(i);
			for(int j=R[i];j!=i;j=R[j])remove(j);
			Dance(d+1);
			for(int j=L[i];j!=i;j=L[j])resume(j);
			resume(i);
			path.pop_back();
		}
	}
}g;
const int inf=(~0u)>>2;
int main()
{
	scanf("%d",&n);
	for(int i=0;i<n;++i)
		scanf("%lf%lf",&pt[i].x,&pt[i].y);
	for(int i=0;i<n;++i)
		getsee(i);
	//for(int i=0;i<n;++i,cout <<endl)for(int j=0;j<n;++j)cout <<see[i][j]<<" ";
	g.init(n,n);
	for(int i=0;i<n;++i)
		for(int j=0;j<n;++j)
		if(see[i][j])g.Link(i+1,j+1);
	g.ansd=n;
	g.Dance(0);
	printf("%d\n",g.ansd);
	return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 3628
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=3005,INF=1<<30;

#define double long double

//幾何ライブラリ
// define double ll をするときは Point の < と == も書き換えよう！

const double eps=1e-11;
const double pi=acos((double)-1.0L);
#define equals(a,b) (fabs((a)-(b))<eps)

double torad(double deg) {return (double)(deg)*pi/180.0;}
double todeg(double ang) {return ang*180.0/pi;}

class Point{
public:
    double x,y;
    
    Point(double x=0,double y=0):x(x),y(y){}
    
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double a){return Point(a*x,a*y);}
    Point operator / (double a){return Point(x/a,y/a);}
    
    double abs(){return sqrt(norm());}
    double norm(){return x*x+y*y;}
    
    bool operator < (const Point &p)const{
        return x+eps<p.x||(equals(x,p.x)&&y+eps<p.y);
        //return x<p.x||(x==p.x&&y<p.y);
    }
    
    bool operator == (const Point &p)const{
        return fabs(x-p.x)<eps/100000&&fabs(y-p.y)<eps/100000;
        //return x==p.x&&y==p.y;
    }
};

typedef Point Vector;

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

struct Segment{
    Point p1,p2;
};

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

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

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

Point turn(Point p,Point c,double pi){
    double q=atan2(p.y-c.y,p.x-c.x);
    q+=pi;
    p=c+Point{cos(q)*abs(p-c),sin(q)*abs(p-c)};
    
    return p;
}
//pをcを中心としてpi回転させる(1周で2π)
//p=cのときnan

//p0,p1,p2の順に見たときどうなるか？

static const int counter_clockwise=1;
static const int clockwise=-1;
static const int online_back=2;
static const int online_front=-2;
static const int on_segment=0;

int ccw(Point p0,Point p1,Point p2){
    Vector a=p1-p0;
    Vector b=p2-p0;
    
    if(cross(a,b)>eps) return counter_clockwise;
    if(cross(a,b)<-eps) return clockwise;
    if(dot(a,b)<-eps) return online_back;
    if(a.norm()<b.norm()) return online_front;
    
    return on_segment;
}

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

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

bool overlap(Segment s1,Segment s2){
    int a=ccw(s1.p1,s1.p2,s2.p1),b=ccw(s1.p1,s1.p2,s2.p2);
    if(a&1||b&1) return 0;
    if(a==2){
        if(b==-2||(b==0&&!(s2.p2==s1.p1))) return 1;
        else return 0;
    }
    if(a==-2){
        if(b==2||(b==0&&!(s2.p2==s1.p2))) return 1;
        else return 0;
    }
    if(a==0){
        if(s1.p1==s2.p1){
            if(b!=2) return 1;
            else return 0;
        }
        else if(s1.p2==s2.p1){
            if(b!=-2) return 1;
            else return 0;
        }
        else return 1;
    }
    return 0;
}
//s1とs2の共通の線分(長さ0より大きい)があるかどうか

typedef Segment Line;

double getDistance(Point a,Point b){
    return abs(a-b);
}

double getDistanceLP(Line l,Point p){
    return abs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1)<0) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2)<0) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistance(Segment s1,Segment s2){
    if(intersect(s1,s2)) return 0.0;
    return min({getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2),getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)});
}

Point getCrossPointS(Segment s1,Segment s2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}//同じ時壊れます

Point getCrossPointL(Line l1,Line l2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    
    return l1.p1+v1*cross(v2,l2.p1-l1.p1)/cross(v2,v1);
}

Segment ParallelSegment(Segment s,double d){
    Vector v={-(s.p2-s.p1).y,(s.p2-s.p1).x};
    v=v/abs(v);
    
    s.p1=s.p1+v*d;
    s.p2=s.p2+v*d;
    
    return s;
}

Point naisin(Point p1,Point p2,Point p3){
    if(p1==p2&&p2==p3&&p3==p1) return p1;
    
    return (p1*abs(p2-p3)+p2*abs(p1-p3)+p3*abs(p1-p2))/(abs(p2-p3)+abs(p1-p3)+abs(p1-p2));
}

Point naisin(Line l1,Line l2,Line l3){
    //平行でない前提
    
    Point p1=getCrossPointL(l1,l2),p2=getCrossPointL(l1,l3),p3=getCrossPointL(l2,l3);
    return naisin(p1,p2,p3);
}

//ネットの適当を書いたのであってるか全く知りません→あってそう

class Circle{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r){}
};

Point CircleCenter(Point a,Point b,Point c){
    Point u=a-b,v=a-c;
    double m1=(norm(a)-norm(b))/2.0,m2=(norm(a)-norm(c))/2.0;
    
    Point res;
    if(cross(u,v)==0.0){
        res.x=1e9;
        res.y=1e9;
        
        return res;
    }
    res.x=(m1*v.y-m2*u.y)/cross(u,v);
    res.y=(m1*v.x-m2*u.x)/cross(v,u);
    
    return res;
}
//3点を通る円の中心を返す

//交わる 0
// c1がc2のinside 1
// c1がc2のoutside 2
// 交わらない 3

int not_intersect(Circle c1,Circle c2){
    double d=getDistance(c1.c,c2.c);
    double r1=c1.r,r2=c2.r;
    if(r1<r2){
        if(d<(r2-r1)) return 1;
    }
    if(r1>r2){
        if(d<(r1-r2)) return 2;
    }
    if(d<=r1+r2) return 0;
    else return 3;
}

pair<Point,Point> segCrossPpoints(Circle c,Line l){
    //assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    return make_pair(pr+e*base,pr-e*base);
}

double arg(Vector p){return atan2(p.y,p.x);}
Vector polar(double a,double r){return Point(cos(r)*a,sin(r)*a);}

//inside(outside)

pair<Point,Point> getCrossPoints(Circle c1,Circle c2){
    //assert(intersect(c1,c2));
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}

vector<Line> Commontangent(Circle c1,Circle c2){
    vector<Line> res;
    Point p=c2.c-c1.c;
    
    if(abs(p)>=(c1.r+c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r+c2.r)+p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r+c2.r)-p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r+c2.r)-p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r+c2.r)+p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    if(abs(p)>=abs(c1.r-c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r-c2.r)+p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r-c2.r)-p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r-c2.r)-p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r-c2.r)+p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    return res;
}

typedef vector<Point> Polygon;

/*
 IN 2
 ON 1
 OUT 0
 */

int contains(Polygon g,Point p){
    int n=int(g.size());
    bool x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(a.y>b.y) swap(a,b);
        if(a.y<eps&&0<b.y&&cross(a,b)<0) x=!x;
        if(abs(cross(a,b))<eps&&dot(a,b)<eps) return 1;
    }
    return (x?2:0);
}

Polygon andrewScan(Polygon s,bool ok){
    Polygon u,l;
    sort(all(s));
    
    if(int(s.size())<3) return s;
    int n=int(s.size());
    
    u.push_back(s[0]);
    u.push_back(s[1]);
    
    l.push_back(s[n-1]);
    l.push_back(s[n-2]);
    
    if(ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])==counter_clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])==counter_clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    if(!ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])!=clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])!=clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    reverse(all(l));
    
    for(int i=int(u.size())-2;i>=1;i--) l.push_back(u[i]);
    
    return l;
}//ok==1なら辺の上も含める

Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon Q;
    for(int i=0;i<si(P);i++){
        Point A=P[i],B=P[(i+1)%si(P)];
        if(ccw(l.p1,l.p2,A)!=-1)Q.push_back(A);
        if(ccw(l.p1,l.p2,A)*ccw(l.p1,l.p2,B)<0) Q.push_back(getCrossPointL(Line{A,B},l));
    }
    return Q;
}

double area(Point a,Point b,Point c){
    b=b-a;
    c=c-a;
    return abs(b.x*c.y-b.y*c.x)/2.0;
}

/*
 
 ll area(Polygon P){
 ll sum=0;
 for(int i=0;i<si(P);i++){
 sum+=cross(P[i],P[(i+1)%si(P)]);
 }
 return abs(sum);
 }
 
 */

// 倍

double area(Polygon &P){
    if(si(P)==0) return 0.0;
    double res=0;
    Point c={0.0,0.0};
    for(int i=0;i<si(P);i++){
        c=c+P[i];
    }
    c=c/si(P);
    
    for(int i=0;i<si(P);i++){
        res+=area(c,P[i],P[(i+1)%si(P)]);
    }
    
    return res;
}

ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}

pair<Point,Vector> perpendicular_bisector(Point a,Point b){
    Point c=(a+b)/2;
    Vector v=b-c;
    swap(v.x,v.y);
    v.x*=-1;
    
    Point p=c;
    if(v.x==0){
        v.y=1;
        p.y=0;
    }
    else if(v.y==0){
        v.x=1;
        p.x=0;
    }
    else{
        if(v.x<0){
            v.x*=-1;
            v.y*=-1;
        }
        ll g=gcd(abs(ll(v.x)),abs(ll(v.y)));
        v.x/=g;
        v.y/=g;
        if(p.x>=0){
            ll d=p.x/v.x;
            p=p-v*d;
        }else{
            ll d=abs(p.x)/v.x;
            p=p+v*d;
            
            if(p.x<0){
                p=p+v;
            }
        }
    }
    
    return mp(p,v);
}
//2倍するなりして整数にしておくこと

int N;
ll S[43];
int ans;

void solve(int u,int cn,ll mask){
    if(cn>=ans) return;
    if(u==N){
        if(mask==(1LL<<N)-1) chmin(ans,cn);
        return;
    }
    solve(u+1,cn+1,mask|S[u]);
    solve(u+1,cn,mask);
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    cout<<fixed<<setprecision(10);
    
    cin>>N;
    vector<Point> P(N);
    for(int i=0;i<N;i++) cin>>P[i].x>>P[i].y;
    
    for(int a=0;a<N;a++){
        S[a]|=(1LL<<a);
        for(int b=a+1;b<N;b++){
            Segment s={P[a],P[b]};
            bool ok=true;
            if(a+1==b||(a==0&&b==N-1)){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                continue;
            }
            for(int i=0;i<N;i++){
                Segment t={P[i],P[(i+1)%N]};
                if(!intersect(s,t)) continue;
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<ccw(s.p1,s.p2,t.p1)<<" "<<ccw(s.p1,s.p2,t.p2)<<endl;
                //cout<<s.p1.x<<" "<<s.p1.y<<" "<<s.p2.x<<" "<<s.p2.y<<" "<<t.p2.x<<" "<<t.p2.y<<endl;
                if(ccw(s.p1,s.p2,t.p1)%2==0&&ccw(s.p1,s.p2,t.p2)%2==0) continue;
                Point p=getCrossPointS(s,t);
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<a<<" "<<b<<" "<<i<<" "<<p.x<<" "<<p.y<<endl;
                {
                    Point q=p-(P[b]-P[a])/abs(P[b]-P[a])*0.00001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(ccw(P[a],P[b],q)==0){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={{q.x,q.y},{1010,q.y}};
                        else c={{q.x,q.y},{q.x,1010}};
                        bool g=false;
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            //if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                            g|=(ccw(d.p1,d.p2,c.p1)==0);
                        }
                        ok&=(f|g);
                    }
                }
                {
                    Point q=p+(P[b]-P[a])/abs(P[b]-P[a])*0.00001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(ccw(P[a],P[b],q)==0){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={{q.x,q.y},{1010,q.y}};
                        else c={{q.x,q.y},{q.x,1010}};
                        bool g=false;
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            //if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                            g|=(ccw(d.p1,d.p2,c.p1)==0);
                        }
                        ok&=(f|g);
                    }
                }
            }
            if(ok){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                //cout<<a<<" "<<b<<endl;
            }
        }
    }
    /*
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if(S[i]>>j&1) cout<<1;
            else cout<<0;
        }
        cout<<endl;
    }
    */
    ans=N;
    
    solve(0,0,0);
    
    cout<<ans<<endl;
}
accuracy: 1
time_ms: 830
memory_kb: 3584
final_rank: 3

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=3005,INF=1<<30;

#define double long double

//幾何ライブラリ
// define double ll をするときは Point の < と == も書き換えよう！

const double eps=1e-6;
const double pi=acos((double)-1.0L);
#define equals(a,b) (fabs((a)-(b))<eps)

double torad(double deg) {return (double)(deg)*pi/180.0;}
double todeg(double ang) {return ang*180.0/pi;}

class Point{
public:
    double x,y;
    
    Point(double x=0,double y=0):x(x),y(y){}
    
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double a){return Point(a*x,a*y);}
    Point operator / (double a){return Point(x/a,y/a);}
    
    double abs(){return sqrt(norm());}
    double norm(){return x*x+y*y;}
    
    bool operator < (const Point &p)const{
        return x+eps<p.x||(equals(x,p.x)&&y+eps<p.y);
        //return x<p.x||(x==p.x&&y<p.y);
    }
    
    bool operator == (const Point &p)const{
        return fabs(x-p.x)<eps/100000&&fabs(y-p.y)<eps/100000;
        //return x==p.x&&y==p.y;
    }
};

typedef Point Vector;

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

struct Segment{
    Point p1,p2;
};

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

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

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

Point turn(Point p,Point c,double pi){
    double q=atan2(p.y-c.y,p.x-c.x);
    q+=pi;
    p=c+Point{cos(q)*abs(p-c),sin(q)*abs(p-c)};
    
    return p;
}
//pをcを中心としてpi回転させる(1周で2π)
//p=cのときnan

//p0,p1,p2の順に見たときどうなるか？

static const int counter_clockwise=1;
static const int clockwise=-1;
static const int online_back=2;
static const int online_front=-2;
static const int on_segment=0;

int ccw(Point p0,Point p1,Point p2){
    Vector a=p1-p0;
    Vector b=p2-p0;
    
    if(cross(a,b)>eps) return counter_clockwise;
    if(cross(a,b)<-eps) return clockwise;
    if(dot(a,b)<-eps) return online_back;
    if(a.norm()<b.norm()) return online_front;
    
    return on_segment;
}

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

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

bool overlap(Segment s1,Segment s2){
    int a=ccw(s1.p1,s1.p2,s2.p1),b=ccw(s1.p1,s1.p2,s2.p2);
    if(a&1||b&1) return 0;
    if(a==2){
        if(b==-2||(b==0&&!(s2.p2==s1.p1))) return 1;
        else return 0;
    }
    if(a==-2){
        if(b==2||(b==0&&!(s2.p2==s1.p2))) return 1;
        else return 0;
    }
    if(a==0){
        if(s1.p1==s2.p1){
            if(b!=2) return 1;
            else return 0;
        }
        else if(s1.p2==s2.p1){
            if(b!=-2) return 1;
            else return 0;
        }
        else return 1;
    }
    return 0;
}
//s1とs2の共通の線分(長さ0より大きい)があるかどうか

typedef Segment Line;

double getDistance(Point a,Point b){
    return abs(a-b);
}

double getDistanceLP(Line l,Point p){
    return abs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1)<0) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2)<0) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistance(Segment s1,Segment s2){
    if(intersect(s1,s2)) return 0.0;
    return min({getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2),getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)});
}

Point getCrossPointS(Segment s1,Segment s2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}//同じ時壊れます

Point getCrossPointL(Line l1,Line l2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    
    return l1.p1+v1*cross(v2,l2.p1-l1.p1)/cross(v2,v1);
}

Segment ParallelSegment(Segment s,double d){
    Vector v={-(s.p2-s.p1).y,(s.p2-s.p1).x};
    v=v/abs(v);
    
    s.p1=s.p1+v*d;
    s.p2=s.p2+v*d;
    
    return s;
}

Point naisin(Point p1,Point p2,Point p3){
    if(p1==p2&&p2==p3&&p3==p1) return p1;
    
    return (p1*abs(p2-p3)+p2*abs(p1-p3)+p3*abs(p1-p2))/(abs(p2-p3)+abs(p1-p3)+abs(p1-p2));
}

Point naisin(Line l1,Line l2,Line l3){
    //平行でない前提
    
    Point p1=getCrossPointL(l1,l2),p2=getCrossPointL(l1,l3),p3=getCrossPointL(l2,l3);
    return naisin(p1,p2,p3);
}

//ネットの適当を書いたのであってるか全く知りません→あってそう

class Circle{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r){}
};

Point CircleCenter(Point a,Point b,Point c){
    Point u=a-b,v=a-c;
    double m1=(norm(a)-norm(b))/2.0,m2=(norm(a)-norm(c))/2.0;
    
    Point res;
    if(cross(u,v)==0.0){
        res.x=1e9;
        res.y=1e9;
        
        return res;
    }
    res.x=(m1*v.y-m2*u.y)/cross(u,v);
    res.y=(m1*v.x-m2*u.x)/cross(v,u);
    
    return res;
}
//3点を通る円の中心を返す

//交わる 0
// c1がc2のinside 1
// c1がc2のoutside 2
// 交わらない 3

int not_intersect(Circle c1,Circle c2){
    double d=getDistance(c1.c,c2.c);
    double r1=c1.r,r2=c2.r;
    if(r1<r2){
        if(d<(r2-r1)) return 1;
    }
    if(r1>r2){
        if(d<(r1-r2)) return 2;
    }
    if(d<=r1+r2) return 0;
    else return 3;
}

pair<Point,Point> segCrossPpoints(Circle c,Line l){
    //assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    return make_pair(pr+e*base,pr-e*base);
}

double arg(Vector p){return atan2(p.y,p.x);}
Vector polar(double a,double r){return Point(cos(r)*a,sin(r)*a);}

//inside(outside)

pair<Point,Point> getCrossPoints(Circle c1,Circle c2){
    //assert(intersect(c1,c2));
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}

vector<Line> Commontangent(Circle c1,Circle c2){
    vector<Line> res;
    Point p=c2.c-c1.c;
    
    if(abs(p)>=(c1.r+c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r+c2.r)+p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r+c2.r)-p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r+c2.r)-p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r+c2.r)+p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    if(abs(p)>=abs(c1.r-c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r-c2.r)+p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r-c2.r)-p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r-c2.r)-p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r-c2.r)+p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    return res;
}

typedef vector<Point> Polygon;

/*
 IN 2
 ON 1
 OUT 0
 */

int contains(Polygon g,Point p){
    int n=int(g.size());
    bool x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(a.y>b.y) swap(a,b);
        if(a.y<eps&&0<b.y&&cross(a,b)<0) x=!x;
        if(abs(cross(a,b))<eps&&dot(a,b)<eps) return 1;
    }
    return (x?2:0);
}

Polygon andrewScan(Polygon s,bool ok){
    Polygon u,l;
    sort(all(s));
    
    if(int(s.size())<3) return s;
    int n=int(s.size());
    
    u.push_back(s[0]);
    u.push_back(s[1]);
    
    l.push_back(s[n-1]);
    l.push_back(s[n-2]);
    
    if(ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])==counter_clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])==counter_clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    if(!ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])!=clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])!=clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    reverse(all(l));
    
    for(int i=int(u.size())-2;i>=1;i--) l.push_back(u[i]);
    
    return l;
}//ok==1なら辺の上も含める

Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon Q;
    for(int i=0;i<si(P);i++){
        Point A=P[i],B=P[(i+1)%si(P)];
        if(ccw(l.p1,l.p2,A)!=-1)Q.push_back(A);
        if(ccw(l.p1,l.p2,A)*ccw(l.p1,l.p2,B)<0) Q.push_back(getCrossPointL(Line{A,B},l));
    }
    return Q;
}

double area(Point a,Point b,Point c){
    b=b-a;
    c=c-a;
    return abs(b.x*c.y-b.y*c.x)/2.0;
}

/*
 
 ll area(Polygon P){
 ll sum=0;
 for(int i=0;i<si(P);i++){
 sum+=cross(P[i],P[(i+1)%si(P)]);
 }
 return abs(sum);
 }
 
 */

// 倍

double area(Polygon &P){
    if(si(P)==0) return 0.0;
    double res=0;
    Point c={0.0,0.0};
    for(int i=0;i<si(P);i++){
        c=c+P[i];
    }
    c=c/si(P);
    
    for(int i=0;i<si(P);i++){
        res+=area(c,P[i],P[(i+1)%si(P)]);
    }
    
    return res;
}

ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}

pair<Point,Vector> perpendicular_bisector(Point a,Point b){
    Point c=(a+b)/2;
    Vector v=b-c;
    swap(v.x,v.y);
    v.x*=-1;
    
    Point p=c;
    if(v.x==0){
        v.y=1;
        p.y=0;
    }
    else if(v.y==0){
        v.x=1;
        p.x=0;
    }
    else{
        if(v.x<0){
            v.x*=-1;
            v.y*=-1;
        }
        ll g=gcd(abs(ll(v.x)),abs(ll(v.y)));
        v.x/=g;
        v.y/=g;
        if(p.x>=0){
            ll d=p.x/v.x;
            p=p-v*d;
        }else{
            ll d=abs(p.x)/v.x;
            p=p+v*d;
            
            if(p.x<0){
                p=p+v;
            }
        }
    }
    
    return mp(p,v);
}
//2倍するなりして整数にしておくこと

int N;
ll S[43];
int ans;

void solve(int u,int cn,ll mask){
    if(cn>=ans) return;
    if(u==N){
        if(mask==(1LL<<N)-1) chmin(ans,cn);
        return;
    }
    solve(u+1,cn+1,mask|S[u]);
    solve(u+1,cn,mask);
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    cout<<fixed<<setprecision(10);
    
    cin>>N;
    vector<Point> P(N);
    for(int i=0;i<N;i++) cin>>P[i].x>>P[i].y;
    
    for(int a=0;a<N;a++){
        S[a]|=(1LL<<a);
        for(int b=a+1;b<N;b++){
            Segment s={P[a],P[b]};
            bool ok=true;
            if(a+1==b||(a==0&&b==N-1)){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                continue;
            }
            for(int i=0;i<N;i++){
                Segment t={P[i],P[(i+1)%N]};
                if(!intersect(s,t)) continue;
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<ccw(s.p1,s.p2,t.p1)<<" "<<ccw(s.p1,s.p2,t.p2)<<endl;
                //cout<<s.p1.x<<" "<<s.p1.y<<" "<<s.p2.x<<" "<<s.p2.y<<" "<<t.p2.x<<" "<<t.p2.y<<endl;
                if(ccw(s.p1,s.p2,t.p1)%2==0&&ccw(s.p1,s.p2,t.p2)%2==0) continue;
                Point p=getCrossPointS(s,t);
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<a<<" "<<b<<" "<<i<<" "<<p.x<<" "<<p.y<<endl;
                {
                    Point q=p-(P[b]-P[a])/abs(P[b]-P[a])*0.0001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(ccw(P[a],P[b],q)==0){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={{q.x,q.y},{1010,q.y}};
                        else c={{q.x,q.y},{q.x,1010}};
                        bool g=false;
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            //if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                            g|=(ccw(d.p1,d.p2,c.p1)%2==0);
                        }
                        ok&=(f|g);
                    }
                }
                {
                    Point q=p+(P[b]-P[a])/abs(P[b]-P[a])*0.0001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(ccw(P[a],P[b],q)==0){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={{q.x,q.y},{1010,q.y}};
                        else c={{q.x,q.y},{q.x,1010}};
                        bool g=false;
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            //if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                            g|=(ccw(d.p1,d.p2,c.p1)%2==0);
                        }
                        ok&=(f|g);
                    }
                }
            }
            if(ok){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                //cout<<a<<" "<<b<<endl;
            }
        }
    }
    /*
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if(S[i]>>j&1) cout<<1;
            else cout<<0;
        }
        cout<<endl;
    }
    */
    ans=N;
    
    solve(0,0,0);
    
    cout<<ans<<endl;
}
accuracy: 0.04
time_ms: 10
memory_kb: 3472
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=3005,INF=1<<30;

#define double long double

//幾何ライブラリ
// define double ll をするときは Point の < と == も書き換えよう！

const double eps=1e-7;
const double pi=acos((double)-1.0L);
#define equals(a,b) (fabs((a)-(b))<eps)

double torad(double deg) {return (double)(deg)*pi/180.0;}
double todeg(double ang) {return ang*180.0/pi;}

class Point{
public:
    double x,y;
    
    Point(double x=0,double y=0):x(x),y(y){}
    
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double a){return Point(a*x,a*y);}
    Point operator / (double a){return Point(x/a,y/a);}
    
    double abs(){return sqrt(norm());}
    double norm(){return x*x+y*y;}
    
    bool operator < (const Point &p)const{
        return x+eps<p.x||(equals(x,p.x)&&y+eps<p.y);
        //return x<p.x||(x==p.x&&y<p.y);
    }
    
    bool operator == (const Point &p)const{
        return fabs(x-p.x)<eps/100000&&fabs(y-p.y)<eps/100000;
        //return x==p.x&&y==p.y;
    }
};

typedef Point Vector;

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

struct Segment{
    Point p1,p2;
};

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

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

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

Point turn(Point p,Point c,double pi){
    double q=atan2(p.y-c.y,p.x-c.x);
    q+=pi;
    p=c+Point{cos(q)*abs(p-c),sin(q)*abs(p-c)};
    
    return p;
}
//pをcを中心としてpi回転させる(1周で2π)
//p=cのときnan

//p0,p1,p2の順に見たときどうなるか？

static const int counter_clockwise=1;
static const int clockwise=-1;
static const int online_back=2;
static const int online_front=-2;
static const int on_segment=0;

int ccw(Point p0,Point p1,Point p2){
    Vector a=p1-p0;
    Vector b=p2-p0;
    
    if(cross(a,b)>eps) return counter_clockwise;
    if(cross(a,b)<-eps) return clockwise;
    if(dot(a,b)<-eps) return online_back;
    if(a.norm()<b.norm()) return online_front;
    
    return on_segment;
}

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

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

bool overlap(Segment s1,Segment s2){
    int a=ccw(s1.p1,s1.p2,s2.p1),b=ccw(s1.p1,s1.p2,s2.p2);
    if(a&1||b&1) return 0;
    if(a==2){
        if(b==-2||(b==0&&!(s2.p2==s1.p1))) return 1;
        else return 0;
    }
    if(a==-2){
        if(b==2||(b==0&&!(s2.p2==s1.p2))) return 1;
        else return 0;
    }
    if(a==0){
        if(s1.p1==s2.p1){
            if(b!=2) return 1;
            else return 0;
        }
        else if(s1.p2==s2.p1){
            if(b!=-2) return 1;
            else return 0;
        }
        else return 1;
    }
    return 0;
}
//s1とs2の共通の線分(長さ0より大きい)があるかどうか

typedef Segment Line;

double getDistance(Point a,Point b){
    return abs(a-b);
}

double getDistanceLP(Line l,Point p){
    return abs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1)<0) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2)<0) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistance(Segment s1,Segment s2){
    if(intersect(s1,s2)) return 0.0;
    return min({getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2),getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)});
}

Point getCrossPointS(Segment s1,Segment s2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}//同じ時壊れます

Point getCrossPointL(Line l1,Line l2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    
    return l1.p1+v1*cross(v2,l2.p1-l1.p1)/cross(v2,v1);
}

Segment ParallelSegment(Segment s,double d){
    Vector v={-(s.p2-s.p1).y,(s.p2-s.p1).x};
    v=v/abs(v);
    
    s.p1=s.p1+v*d;
    s.p2=s.p2+v*d;
    
    return s;
}

Point naisin(Point p1,Point p2,Point p3){
    if(p1==p2&&p2==p3&&p3==p1) return p1;
    
    return (p1*abs(p2-p3)+p2*abs(p1-p3)+p3*abs(p1-p2))/(abs(p2-p3)+abs(p1-p3)+abs(p1-p2));
}

Point naisin(Line l1,Line l2,Line l3){
    //平行でない前提
    
    Point p1=getCrossPointL(l1,l2),p2=getCrossPointL(l1,l3),p3=getCrossPointL(l2,l3);
    return naisin(p1,p2,p3);
}

//ネットの適当を書いたのであってるか全く知りません→あってそう

class Circle{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r){}
};

Point CircleCenter(Point a,Point b,Point c){
    Point u=a-b,v=a-c;
    double m1=(norm(a)-norm(b))/2.0,m2=(norm(a)-norm(c))/2.0;
    
    Point res;
    if(cross(u,v)==0.0){
        res.x=1e9;
        res.y=1e9;
        
        return res;
    }
    res.x=(m1*v.y-m2*u.y)/cross(u,v);
    res.y=(m1*v.x-m2*u.x)/cross(v,u);
    
    return res;
}
//3点を通る円の中心を返す

//交わる 0
// c1がc2のinside 1
// c1がc2のoutside 2
// 交わらない 3

int not_intersect(Circle c1,Circle c2){
    double d=getDistance(c1.c,c2.c);
    double r1=c1.r,r2=c2.r;
    if(r1<r2){
        if(d<(r2-r1)) return 1;
    }
    if(r1>r2){
        if(d<(r1-r2)) return 2;
    }
    if(d<=r1+r2) return 0;
    else return 3;
}

pair<Point,Point> segCrossPpoints(Circle c,Line l){
    //assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    return make_pair(pr+e*base,pr-e*base);
}

double arg(Vector p){return atan2(p.y,p.x);}
Vector polar(double a,double r){return Point(cos(r)*a,sin(r)*a);}

//inside(outside)

pair<Point,Point> getCrossPoints(Circle c1,Circle c2){
    //assert(intersect(c1,c2));
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}

vector<Line> Commontangent(Circle c1,Circle c2){
    vector<Line> res;
    Point p=c2.c-c1.c;
    
    if(abs(p)>=(c1.r+c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r+c2.r)+p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r+c2.r)-p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r+c2.r)-p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r+c2.r)+p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    if(abs(p)>=abs(c1.r-c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r-c2.r)+p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r-c2.r)-p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r-c2.r)-p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r-c2.r)+p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    return res;
}

typedef vector<Point> Polygon;

/*
 IN 2
 ON 1
 OUT 0
 */

int contains(Polygon g,Point p){
    int n=int(g.size());
    bool x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(a.y>b.y) swap(a,b);
        if(a.y<eps&&0<b.y&&cross(a,b)<0) x=!x;
        if(abs(cross(a,b))<eps&&dot(a,b)<eps) return 1;
    }
    return (x?2:0);
}

Polygon andrewScan(Polygon s,bool ok){
    Polygon u,l;
    sort(all(s));
    
    if(int(s.size())<3) return s;
    int n=int(s.size());
    
    u.push_back(s[0]);
    u.push_back(s[1]);
    
    l.push_back(s[n-1]);
    l.push_back(s[n-2]);
    
    if(ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])==counter_clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])==counter_clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    if(!ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])!=clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])!=clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    reverse(all(l));
    
    for(int i=int(u.size())-2;i>=1;i--) l.push_back(u[i]);
    
    return l;
}//ok==1なら辺の上も含める

Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon Q;
    for(int i=0;i<si(P);i++){
        Point A=P[i],B=P[(i+1)%si(P)];
        if(ccw(l.p1,l.p2,A)!=-1)Q.push_back(A);
        if(ccw(l.p1,l.p2,A)*ccw(l.p1,l.p2,B)<0) Q.push_back(getCrossPointL(Line{A,B},l));
    }
    return Q;
}

double area(Point a,Point b,Point c){
    b=b-a;
    c=c-a;
    return abs(b.x*c.y-b.y*c.x)/2.0;
}

/*
 
 ll area(Polygon P){
 ll sum=0;
 for(int i=0;i<si(P);i++){
 sum+=cross(P[i],P[(i+1)%si(P)]);
 }
 return abs(sum);
 }
 
 */

// 倍

double area(Polygon &P){
    if(si(P)==0) return 0.0;
    double res=0;
    Point c={0.0,0.0};
    for(int i=0;i<si(P);i++){
        c=c+P[i];
    }
    c=c/si(P);
    
    for(int i=0;i<si(P);i++){
        res+=area(c,P[i],P[(i+1)%si(P)]);
    }
    
    return res;
}

ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}

pair<Point,Vector> perpendicular_bisector(Point a,Point b){
    Point c=(a+b)/2;
    Vector v=b-c;
    swap(v.x,v.y);
    v.x*=-1;
    
    Point p=c;
    if(v.x==0){
        v.y=1;
        p.y=0;
    }
    else if(v.y==0){
        v.x=1;
        p.x=0;
    }
    else{
        if(v.x<0){
            v.x*=-1;
            v.y*=-1;
        }
        ll g=gcd(abs(ll(v.x)),abs(ll(v.y)));
        v.x/=g;
        v.y/=g;
        if(p.x>=0){
            ll d=p.x/v.x;
            p=p-v*d;
        }else{
            ll d=abs(p.x)/v.x;
            p=p+v*d;
            
            if(p.x<0){
                p=p+v;
            }
        }
    }
    
    return mp(p,v);
}
//2倍するなりして整数にしておくこと

int N;
ll S[43];
int ans;

void solve(int u,int cn,ll mask){
    if(cn>=ans) return;
    if(u==N){
        if(mask==(1LL<<N)-1) chmin(ans,cn);
        return;
    }
    solve(u+1,cn+1,mask|S[u]);
    solve(u+1,cn,mask);
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    cout<<fixed<<setprecision(10);
    
    cin>>N;
    vector<Point> P(N);
    for(int i=0;i<N;i++) cin>>P[i].x>>P[i].y;
    
    for(int a=0;a<N;a++){
        S[a]|=(1LL<<a);
        for(int b=a+1;b<N;b++){
            Segment s={P[a],P[b]};
            bool ok=true;
            if(a+1==b||(a==0&&b==N-1)){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                continue;
            }
            for(int i=0;i<N;i++){
                Segment t={P[i],P[(i+1)%N]};
                if(!intersect(s,t)) continue;
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<ccw(s.p1,s.p2,t.p1)<<" "<<ccw(s.p1,s.p2,t.p2)<<endl;
                //cout<<s.p1.x<<" "<<s.p1.y<<" "<<s.p2.x<<" "<<s.p2.y<<" "<<t.p2.x<<" "<<t.p2.y<<endl;
                if(ccw(s.p1,s.p2,t.p1)%2==0&&ccw(s.p1,s.p2,t.p2)%2==0) continue;
                Point p=getCrossPointS(s,t);
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<a<<" "<<b<<" "<<i<<" "<<p.x<<" "<<p.y<<endl;
                {
                    Point q=p-(P[b]-P[a])/abs(P[b]-P[a])*0.000001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(ccw(P[a],P[b],q)==0&&getDistance(P[a],q)>eps&&getDistance(P[b],q)>eps){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={{q.x+eps,q.y},{1010,q.y}};
                        else c={{q.x,q.y+eps},{q.x,1010}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            //if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
                {
                    Point q=p+(P[b]-P[a])/abs(P[b]-P[a])*0.000001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(ccw(P[a],P[b],q)==0&&getDistance(P[a],q)>eps&&getDistance(P[b],q)>eps){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={{q.x+eps,q.y},{1010,q.y}};
                        else c={{q.x,q.y+eps},{q.x,1010}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            //if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
            }
            if(ok){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                //cout<<a<<" "<<b<<endl;
            }
        }
    }
    /*
    for(int i=0;i<N;i++){
        for(int j=0;j<N;j++){
            if(S[i]>>j&1) cout<<1;
            else cout<<0;
        }
        cout<<endl;
    }
    */
    ans=N;
    
    solve(0,0,0);
    
    cout<<ans<<endl;
}
accuracy: 0.1
time_ms: 730
memory_kb: 3476
final_rank: 9

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=3005,INF=1<<30;

#define double long double

//幾何ライブラリ
// define double ll をするときは Point の < と == も書き換えよう！

const double eps=1e-10;
const double pi=acos((double)-1.0L);
#define equals(a,b) (fabs((a)-(b))<eps)

double torad(double deg) {return (double)(deg)*pi/180.0;}
double todeg(double ang) {return ang*180.0/pi;}

class Point{
public:
    double x,y;
    
    Point(double x=0,double y=0):x(x),y(y){}
    
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double a){return Point(a*x,a*y);}
    Point operator / (double a){return Point(x/a,y/a);}
    
    double abs(){return sqrt(norm());}
    double norm(){return x*x+y*y;}
    
    bool operator < (const Point &p)const{
        return x+eps<p.x||(equals(x,p.x)&&y+eps<p.y);
        //return x<p.x||(x==p.x&&y<p.y);
    }
    
    bool operator == (const Point &p)const{
        return fabs(x-p.x)<eps/100000&&fabs(y-p.y)<eps/100000;
        //return x==p.x&&y==p.y;
    }
};

typedef Point Vector;

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

struct Segment{
    Point p1,p2;
};

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

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

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

Point turn(Point p,Point c,double pi){
    double q=atan2(p.y-c.y,p.x-c.x);
    q+=pi;
    p=c+Point{cos(q)*abs(p-c),sin(q)*abs(p-c)};
    
    return p;
}
//pをcを中心としてpi回転させる(1周で2π)
//p=cのときnan

//p0,p1,p2の順に見たときどうなるか？

static const int counter_clockwise=1;
static const int clockwise=-1;
static const int online_back=2;
static const int online_front=-2;
static const int on_segment=0;

int ccw(Point p0,Point p1,Point p2){
    Vector a=p1-p0;
    Vector b=p2-p0;
    
    if(cross(a,b)>eps) return counter_clockwise;
    if(cross(a,b)<-eps) return clockwise;
    if(dot(a,b)<-eps) return online_back;
    if(a.norm()<b.norm()) return online_front;
    
    return on_segment;
}

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

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

bool overlap(Segment s1,Segment s2){
    int a=ccw(s1.p1,s1.p2,s2.p1),b=ccw(s1.p1,s1.p2,s2.p2);
    if(a&1||b&1) return 0;
    if(a==2){
        if(b==-2||(b==0&&!(s2.p2==s1.p1))) return 1;
        else return 0;
    }
    if(a==-2){
        if(b==2||(b==0&&!(s2.p2==s1.p2))) return 1;
        else return 0;
    }
    if(a==0){
        if(s1.p1==s2.p1){
            if(b!=2) return 1;
            else return 0;
        }
        else if(s1.p2==s2.p1){
            if(b!=-2) return 1;
            else return 0;
        }
        else return 1;
    }
    return 0;
}
//s1とs2の共通の線分(長さ0より大きい)があるかどうか

typedef Segment Line;

double getDistance(Point a,Point b){
    return abs(a-b);
}

double getDistanceLP(Line l,Point p){
    return abs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1)<0) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2)<0) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistance(Segment s1,Segment s2){
    if(intersect(s1,s2)) return 0.0;
    return min({getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2),getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)});
}

Point getCrossPointS(Segment s1,Segment s2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}//同じ時壊れます

Point getCrossPointL(Line l1,Line l2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    
    return l1.p1+v1*cross(v2,l2.p1-l1.p1)/cross(v2,v1);
}

Segment ParallelSegment(Segment s,double d){
    Vector v={-(s.p2-s.p1).y,(s.p2-s.p1).x};
    v=v/abs(v);
    
    s.p1=s.p1+v*d;
    s.p2=s.p2+v*d;
    
    return s;
}

Point naisin(Point p1,Point p2,Point p3){
    if(p1==p2&&p2==p3&&p3==p1) return p1;
    
    return (p1*abs(p2-p3)+p2*abs(p1-p3)+p3*abs(p1-p2))/(abs(p2-p3)+abs(p1-p3)+abs(p1-p2));
}

Point naisin(Line l1,Line l2,Line l3){
    //平行でない前提
    
    Point p1=getCrossPointL(l1,l2),p2=getCrossPointL(l1,l3),p3=getCrossPointL(l2,l3);
    return naisin(p1,p2,p3);
}

//ネットの適当を書いたのであってるか全く知りません→あってそう

class Circle{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r){}
};

Point CircleCenter(Point a,Point b,Point c){
    Point u=a-b,v=a-c;
    double m1=(norm(a)-norm(b))/2.0,m2=(norm(a)-norm(c))/2.0;
    
    Point res;
    if(cross(u,v)==0.0){
        res.x=1e9;
        res.y=1e9;
        
        return res;
    }
    res.x=(m1*v.y-m2*u.y)/cross(u,v);
    res.y=(m1*v.x-m2*u.x)/cross(v,u);
    
    return res;
}
//3点を通る円の中心を返す

//交わる 0
// c1がc2のinside 1
// c1がc2のoutside 2
// 交わらない 3

int not_intersect(Circle c1,Circle c2){
    double d=getDistance(c1.c,c2.c);
    double r1=c1.r,r2=c2.r;
    if(r1<r2){
        if(d<(r2-r1)) return 1;
    }
    if(r1>r2){
        if(d<(r1-r2)) return 2;
    }
    if(d<=r1+r2) return 0;
    else return 3;
}

pair<Point,Point> segCrossPpoints(Circle c,Line l){
    //assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    return make_pair(pr+e*base,pr-e*base);
}

double arg(Vector p){return atan2(p.y,p.x);}
Vector polar(double a,double r){return Point(cos(r)*a,sin(r)*a);}

//inside(outside)

pair<Point,Point> getCrossPoints(Circle c1,Circle c2){
    //assert(intersect(c1,c2));
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}

vector<Line> Commontangent(Circle c1,Circle c2){
    vector<Line> res;
    Point p=c2.c-c1.c;
    
    if(abs(p)>=(c1.r+c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r+c2.r)+p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r+c2.r)-p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r+c2.r)-p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r+c2.r)+p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    if(abs(p)>=abs(c1.r-c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r-c2.r)+p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r-c2.r)-p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r-c2.r)-p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r-c2.r)+p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    return res;
}

typedef vector<Point> Polygon;

/*
 IN 2
 ON 1
 OUT 0
 */

int contains(Polygon g,Point p){
    int n=int(g.size());
    bool x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(a.y>b.y) swap(a,b);
        if(a.y<eps&&0<b.y&&cross(a,b)<0) x=!x;
        if(abs(cross(a,b))<eps&&dot(a,b)<eps) return 1;
    }
    return (x?2:0);
}

Polygon andrewScan(Polygon s,bool ok){
    Polygon u,l;
    sort(all(s));
    
    if(int(s.size())<3) return s;
    int n=int(s.size());
    
    u.push_back(s[0]);
    u.push_back(s[1]);
    
    l.push_back(s[n-1]);
    l.push_back(s[n-2]);
    
    if(ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])==counter_clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])==counter_clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    if(!ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])!=clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])!=clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    reverse(all(l));
    
    for(int i=int(u.size())-2;i>=1;i--) l.push_back(u[i]);
    
    return l;
}//ok==1なら辺の上も含める

Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon Q;
    for(int i=0;i<si(P);i++){
        Point A=P[i],B=P[(i+1)%si(P)];
        if(ccw(l.p1,l.p2,A)!=-1)Q.push_back(A);
        if(ccw(l.p1,l.p2,A)*ccw(l.p1,l.p2,B)<0) Q.push_back(getCrossPointL(Line{A,B},l));
    }
    return Q;
}

double area(Point a,Point b,Point c){
    b=b-a;
    c=c-a;
    return abs(b.x*c.y-b.y*c.x)/2.0;
}

/*
 
 ll area(Polygon P){
 ll sum=0;
 for(int i=0;i<si(P);i++){
 sum+=cross(P[i],P[(i+1)%si(P)]);
 }
 return abs(sum);
 }
 
 */

// 倍

double area(Polygon &P){
    if(si(P)==0) return 0.0;
    double res=0;
    Point c={0.0,0.0};
    for(int i=0;i<si(P);i++){
        c=c+P[i];
    }
    c=c/si(P);
    
    for(int i=0;i<si(P);i++){
        res+=area(c,P[i],P[(i+1)%si(P)]);
    }
    
    return res;
}

ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}

pair<Point,Vector> perpendicular_bisector(Point a,Point b){
    Point c=(a+b)/2;
    Vector v=b-c;
    swap(v.x,v.y);
    v.x*=-1;
    
    Point p=c;
    if(v.x==0){
        v.y=1;
        p.y=0;
    }
    else if(v.y==0){
        v.x=1;
        p.x=0;
    }
    else{
        if(v.x<0){
            v.x*=-1;
            v.y*=-1;
        }
        ll g=gcd(abs(ll(v.x)),abs(ll(v.y)));
        v.x/=g;
        v.y/=g;
        if(p.x>=0){
            ll d=p.x/v.x;
            p=p-v*d;
        }else{
            ll d=abs(p.x)/v.x;
            p=p+v*d;
            
            if(p.x<0){
                p=p+v;
            }
        }
    }
    
    return mp(p,v);
}
//2倍するなりして整数にしておくこと

int N;
ll S[43];
int ans;

void solve(int u,int cn,ll mask){
    if(cn>=ans) return;
    if(u==N){
        if(mask==(1LL<<N)-1) chmin(ans,cn);
        return;
    }
    solve(u+1,cn+1,mask|S[u]);
    solve(u+1,cn,mask);
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    //cout<<fixed<<setprecision(10);
    
    cin>>N;
    vector<Point> P(N);
    for(int i=0;i<N;i++) cin>>P[i].x>>P[i].y;
    
    for(int a=0;a<N;a++){
        S[a]|=(1LL<<a);
        for(int b=a+1;b<N;b++){
            Segment s={P[a],P[b]};
            bool ok=true;
            if(a+1==b||(a==0&&b==N-1)){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                continue;
            }
            for(int i=0;i<N;i++){
                Segment t={P[i],P[(i+1)%N]};
                if(!intersect(s,t)) continue;
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<ccw(s.p1,s.p2,t.p1)<<" "<<ccw(s.p1,s.p2,t.p2)<<endl;
                //cout<<s.p1.x<<" "<<s.p1.y<<" "<<s.p2.x<<" "<<s.p2.y<<" "<<t.p2.x<<" "<<t.p2.y<<endl;
                if(ccw(s.p1,s.p2,t.p1)%2==0&&ccw(s.p1,s.p2,t.p2)%2==0) continue;
                Point p=getCrossPointS(s,t);
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<a<<" "<<b<<" "<<i<<" "<<p.x<<" "<<p.y<<endl;
                {
                    Point q=p-(P[b]-P[a])/abs(P[b]-P[a])*0.00001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(ccw(P[a],P[b],q)==0){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={q,{1100,q.y}};
                        else c={q,{q.x,1100}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            //if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
                {
                    Point q=p+(P[b]-P[a])/abs(P[b]-P[a])*0.00001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(ccw(P[a],P[b],q)==0){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={q,{1100,q.y}};
                        else c={q,{q.x,1100}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            //if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
            }
            if(ok){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                //cout<<a<<" "<<b<<endl;
            }
        }
    }
    
    ans=N;
    
    solve(0,0,0);
    
    cout<<ans<<endl;
}
accuracy: 0.1
time_ms: 770
memory_kb: 3404
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=3005,INF=1<<30;

#define double long double

//幾何ライブラリ
// define double ll をするときは Point の < と == も書き換えよう！

const double eps=1e-13;
const double pi=acos((double)-1.0L);
#define equals(a,b) (fabs((a)-(b))<eps)

double torad(double deg) {return (double)(deg)*pi/180.0;}
double todeg(double ang) {return ang*180.0/pi;}

class Point{
public:
    double x,y;
    
    Point(double x=0,double y=0):x(x),y(y){}
    
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double a){return Point(a*x,a*y);}
    Point operator / (double a){return Point(x/a,y/a);}
    
    double abs(){return sqrt(norm());}
    double norm(){return x*x+y*y;}
    
    bool operator < (const Point &p)const{
        return x+eps<p.x||(equals(x,p.x)&&y+eps<p.y);
        //return x<p.x||(x==p.x&&y<p.y);
    }
    
    bool operator == (const Point &p)const{
        return fabs(x-p.x)<eps/100000&&fabs(y-p.y)<eps/100000;
        //return x==p.x&&y==p.y;
    }
};

typedef Point Vector;

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

struct Segment{
    Point p1,p2;
};

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

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

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

Point turn(Point p,Point c,double pi){
    double q=atan2(p.y-c.y,p.x-c.x);
    q+=pi;
    p=c+Point{cos(q)*abs(p-c),sin(q)*abs(p-c)};
    
    return p;
}
//pをcを中心としてpi回転させる(1周で2π)
//p=cのときnan

//p0,p1,p2の順に見たときどうなるか？

static const int counter_clockwise=1;
static const int clockwise=-1;
static const int online_back=2;
static const int online_front=-2;
static const int on_segment=0;

int ccw(Point p0,Point p1,Point p2){
    Vector a=p1-p0;
    Vector b=p2-p0;
    
    if(cross(a,b)>eps) return counter_clockwise;
    if(cross(a,b)<-eps) return clockwise;
    if(dot(a,b)<-eps) return online_back;
    if(a.norm()<b.norm()) return online_front;
    
    return on_segment;
}

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

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

bool overlap(Segment s1,Segment s2){
    int a=ccw(s1.p1,s1.p2,s2.p1),b=ccw(s1.p1,s1.p2,s2.p2);
    if(a&1||b&1) return 0;
    if(a==2){
        if(b==-2||(b==0&&!(s2.p2==s1.p1))) return 1;
        else return 0;
    }
    if(a==-2){
        if(b==2||(b==0&&!(s2.p2==s1.p2))) return 1;
        else return 0;
    }
    if(a==0){
        if(s1.p1==s2.p1){
            if(b!=2) return 1;
            else return 0;
        }
        else if(s1.p2==s2.p1){
            if(b!=-2) return 1;
            else return 0;
        }
        else return 1;
    }
    return 0;
}
//s1とs2の共通の線分(長さ0より大きい)があるかどうか

typedef Segment Line;

double getDistance(Point a,Point b){
    return abs(a-b);
}

double getDistanceLP(Line l,Point p){
    return abs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1)<-eps) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2)<-eps) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistance(Segment s1,Segment s2){
    if(intersect(s1,s2)) return 0.0;
    return min({getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2),getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)});
}

Point getCrossPointS(Segment s1,Segment s2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}//同じ時壊れます

Point getCrossPointL(Line l1,Line l2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    
    return l1.p1+v1*cross(v2,l2.p1-l1.p1)/cross(v2,v1);
}

Segment ParallelSegment(Segment s,double d){
    Vector v={-(s.p2-s.p1).y,(s.p2-s.p1).x};
    v=v/abs(v);
    
    s.p1=s.p1+v*d;
    s.p2=s.p2+v*d;
    
    return s;
}

Point naisin(Point p1,Point p2,Point p3){
    if(p1==p2&&p2==p3&&p3==p1) return p1;
    
    return (p1*abs(p2-p3)+p2*abs(p1-p3)+p3*abs(p1-p2))/(abs(p2-p3)+abs(p1-p3)+abs(p1-p2));
}

Point naisin(Line l1,Line l2,Line l3){
    //平行でない前提
    
    Point p1=getCrossPointL(l1,l2),p2=getCrossPointL(l1,l3),p3=getCrossPointL(l2,l3);
    return naisin(p1,p2,p3);
}

//ネットの適当を書いたのであってるか全く知りません→あってそう

class Circle{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r){}
};

Point CircleCenter(Point a,Point b,Point c){
    Point u=a-b,v=a-c;
    double m1=(norm(a)-norm(b))/2.0,m2=(norm(a)-norm(c))/2.0;
    
    Point res;
    if(cross(u,v)==0.0){
        res.x=1e9;
        res.y=1e9;
        
        return res;
    }
    res.x=(m1*v.y-m2*u.y)/cross(u,v);
    res.y=(m1*v.x-m2*u.x)/cross(v,u);
    
    return res;
}
//3点を通る円の中心を返す

//交わる 0
// c1がc2のinside 1
// c1がc2のoutside 2
// 交わらない 3

int not_intersect(Circle c1,Circle c2){
    double d=getDistance(c1.c,c2.c);
    double r1=c1.r,r2=c2.r;
    if(r1<r2){
        if(d<(r2-r1)) return 1;
    }
    if(r1>r2){
        if(d<(r1-r2)) return 2;
    }
    if(d<=r1+r2) return 0;
    else return 3;
}

pair<Point,Point> segCrossPpoints(Circle c,Line l){
    //assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    return make_pair(pr+e*base,pr-e*base);
}

double arg(Vector p){return atan2(p.y,p.x);}
Vector polar(double a,double r){return Point(cos(r)*a,sin(r)*a);}

//inside(outside)

pair<Point,Point> getCrossPoints(Circle c1,Circle c2){
    //assert(intersect(c1,c2));
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}

vector<Line> Commontangent(Circle c1,Circle c2){
    vector<Line> res;
    Point p=c2.c-c1.c;
    
    if(abs(p)>=(c1.r+c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r+c2.r)+p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r+c2.r)-p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r+c2.r)-p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r+c2.r)+p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    if(abs(p)>=abs(c1.r-c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r-c2.r)+p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r-c2.r)-p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r-c2.r)-p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r-c2.r)+p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    return res;
}

typedef vector<Point> Polygon;

/*
 IN 2
 ON 1
 OUT 0
 */

int contains(Polygon g,Point p){
    int n=int(g.size());
    bool x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(a.y>b.y) swap(a,b);
        if(a.y<eps&&0<b.y&&cross(a,b)<0) x=!x;
        if(abs(cross(a,b))<eps&&dot(a,b)<eps) return 1;
    }
    return (x?2:0);
}

Polygon andrewScan(Polygon s,bool ok){
    Polygon u,l;
    sort(all(s));
    
    if(int(s.size())<3) return s;
    int n=int(s.size());
    
    u.push_back(s[0]);
    u.push_back(s[1]);
    
    l.push_back(s[n-1]);
    l.push_back(s[n-2]);
    
    if(ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])==counter_clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])==counter_clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    if(!ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])!=clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])!=clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    reverse(all(l));
    
    for(int i=int(u.size())-2;i>=1;i--) l.push_back(u[i]);
    
    return l;
}//ok==1なら辺の上も含める

Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon Q;
    for(int i=0;i<si(P);i++){
        Point A=P[i],B=P[(i+1)%si(P)];
        if(ccw(l.p1,l.p2,A)!=-1)Q.push_back(A);
        if(ccw(l.p1,l.p2,A)*ccw(l.p1,l.p2,B)<0) Q.push_back(getCrossPointL(Line{A,B},l));
    }
    return Q;
}

double area(Point a,Point b,Point c){
    b=b-a;
    c=c-a;
    return abs(b.x*c.y-b.y*c.x)/2.0;
}

/*
 
 ll area(Polygon P){
 ll sum=0;
 for(int i=0;i<si(P);i++){
 sum+=cross(P[i],P[(i+1)%si(P)]);
 }
 return abs(sum);
 }
 
 */

// 倍

double area(Polygon &P){
    if(si(P)==0) return 0.0;
    double res=0;
    Point c={0.0,0.0};
    for(int i=0;i<si(P);i++){
        c=c+P[i];
    }
    c=c/si(P);
    
    for(int i=0;i<si(P);i++){
        res+=area(c,P[i],P[(i+1)%si(P)]);
    }
    
    return res;
}

ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}

pair<Point,Vector> perpendicular_bisector(Point a,Point b){
    Point c=(a+b)/2;
    Vector v=b-c;
    swap(v.x,v.y);
    v.x*=-1;
    
    Point p=c;
    if(v.x==0){
        v.y=1;
        p.y=0;
    }
    else if(v.y==0){
        v.x=1;
        p.x=0;
    }
    else{
        if(v.x<0){
            v.x*=-1;
            v.y*=-1;
        }
        ll g=gcd(abs(ll(v.x)),abs(ll(v.y)));
        v.x/=g;
        v.y/=g;
        if(p.x>=0){
            ll d=p.x/v.x;
            p=p-v*d;
        }else{
            ll d=abs(p.x)/v.x;
            p=p+v*d;
            
            if(p.x<0){
                p=p+v;
            }
        }
    }
    
    return mp(p,v);
}
//2倍するなりして整数にしておくこと

int N;
ll S[43];
int ans;

void solve(int u,int cn,ll mask){
    if(cn>=ans) return;
    if(u==N){
        if(mask==(1LL<<N)-1) chmin(ans,cn);
        return;
    }
    solve(u+1,cn+1,mask|S[u]);
    solve(u+1,cn,mask);
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    //cout<<fixed<<setprecision(10);
    
    cin>>N;
    vector<Point> P(N);
    for(int i=0;i<N;i++) cin>>P[i].x>>P[i].y;
    
    for(int a=0;a<N;a++){
        S[a]|=(1LL<<a);
        for(int b=a+1;b<N;b++){
            Segment s={P[a],P[b]};
            bool ok=true;
            if(a+1==b||(a==0&&b==N-1)){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                continue;
            }
            for(int i=0;i<N;i++){
                Segment t={P[i],P[(i+1)%N]};
                if(!intersect(s,t)) continue;
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<ccw(s.p1,s.p2,t.p1)<<" "<<ccw(s.p1,s.p2,t.p2)<<endl;
                //cout<<s.p1.x<<" "<<s.p1.y<<" "<<s.p2.x<<" "<<s.p2.y<<" "<<t.p2.x<<" "<<t.p2.y<<endl;
                if(ccw(s.p1,s.p2,t.p1)%2==0&&ccw(s.p1,s.p2,t.p2)%2==0) continue;
                Point p=getCrossPointS(s,t);
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<a<<" "<<b<<" "<<i<<" "<<p.x<<" "<<p.y<<endl;
                {
                    Point q=p-(P[b]-P[a])/abs(P[b]-P[a])*0.00001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(ccw(P[a],P[b],q)==0){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={q,{1100,q.y}};
                        else c={q,{q.x,1100}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
                {
                    Point q=p+(P[b]-P[a])/abs(P[b]-P[a])*0.00001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(ccw(P[a],P[b],q)==0){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={q,{1100,q.y}};
                        else c={q,{q.x,1100}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
            }
            if(ok){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                //cout<<a<<" "<<b<<endl;
            }
        }
    }
    
    ans=N;
    
    solve(0,0,0);
    
    cout<<ans<<endl;
}
accuracy: 0.1
time_ms: 730
memory_kb: 3540
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=3005,INF=1<<30;

#define double long double

//幾何ライブラリ
// define double ll をするときは Point の < と == も書き換えよう！

const double eps=1e-10;
const double pi=acos((double)-1.0L);
#define equals(a,b) (fabs((a)-(b))<eps)

double torad(double deg) {return (double)(deg)*pi/180.0;}
double todeg(double ang) {return ang*180.0/pi;}

class Point{
public:
    double x,y;
    
    Point(double x=0,double y=0):x(x),y(y){}
    
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double a){return Point(a*x,a*y);}
    Point operator / (double a){return Point(x/a,y/a);}
    
    double abs(){return sqrt(norm());}
    double norm(){return x*x+y*y;}
    
    bool operator < (const Point &p)const{
        return x+eps<p.x||(equals(x,p.x)&&y+eps<p.y);
        //return x<p.x||(x==p.x&&y<p.y);
    }
    
    bool operator == (const Point &p)const{
        return fabs(x-p.x)<eps/100000&&fabs(y-p.y)<eps/100000;
        //return x==p.x&&y==p.y;
    }
};

typedef Point Vector;

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

struct Segment{
    Point p1,p2;
};

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

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

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

Point turn(Point p,Point c,double pi){
    double q=atan2(p.y-c.y,p.x-c.x);
    q+=pi;
    p=c+Point{cos(q)*abs(p-c),sin(q)*abs(p-c)};
    
    return p;
}
//pをcを中心としてpi回転させる(1周で2π)
//p=cのときnan

//p0,p1,p2の順に見たときどうなるか？

static const int counter_clockwise=1;
static const int clockwise=-1;
static const int online_back=2;
static const int online_front=-2;
static const int on_segment=0;

int ccw(Point p0,Point p1,Point p2){
    Vector a=p1-p0;
    Vector b=p2-p0;
    
    if(cross(a,b)>eps) return counter_clockwise;
    if(cross(a,b)<-eps) return clockwise;
    if(dot(a,b)<-eps) return online_back;
    if(a.norm()<b.norm()) return online_front;
    
    return on_segment;
}

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

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

bool overlap(Segment s1,Segment s2){
    int a=ccw(s1.p1,s1.p2,s2.p1),b=ccw(s1.p1,s1.p2,s2.p2);
    if(a&1||b&1) return 0;
    if(a==2){
        if(b==-2||(b==0&&!(s2.p2==s1.p1))) return 1;
        else return 0;
    }
    if(a==-2){
        if(b==2||(b==0&&!(s2.p2==s1.p2))) return 1;
        else return 0;
    }
    if(a==0){
        if(s1.p1==s2.p1){
            if(b!=2) return 1;
            else return 0;
        }
        else if(s1.p2==s2.p1){
            if(b!=-2) return 1;
            else return 0;
        }
        else return 1;
    }
    return 0;
}
//s1とs2の共通の線分(長さ0より大きい)があるかどうか

typedef Segment Line;

double getDistance(Point a,Point b){
    return abs(a-b);
}

double getDistanceLP(Line l,Point p){
    return abs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1)<0.0) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2)<0.0) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistance(Segment s1,Segment s2){
    if(intersect(s1,s2)) return 0.0;
    return min({getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2),getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)});
}

Point getCrossPointS(Segment s1,Segment s2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}//同じ時壊れます

Point getCrossPointL(Line l1,Line l2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    
    return l1.p1+v1*cross(v2,l2.p1-l1.p1)/cross(v2,v1);
}

Segment ParallelSegment(Segment s,double d){
    Vector v={-(s.p2-s.p1).y,(s.p2-s.p1).x};
    v=v/abs(v);
    
    s.p1=s.p1+v*d;
    s.p2=s.p2+v*d;
    
    return s;
}

Point naisin(Point p1,Point p2,Point p3){
    if(p1==p2&&p2==p3&&p3==p1) return p1;
    
    return (p1*abs(p2-p3)+p2*abs(p1-p3)+p3*abs(p1-p2))/(abs(p2-p3)+abs(p1-p3)+abs(p1-p2));
}

Point naisin(Line l1,Line l2,Line l3){
    //平行でない前提
    
    Point p1=getCrossPointL(l1,l2),p2=getCrossPointL(l1,l3),p3=getCrossPointL(l2,l3);
    return naisin(p1,p2,p3);
}

//ネットの適当を書いたのであってるか全く知りません→あってそう

class Circle{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r){}
};

Point CircleCenter(Point a,Point b,Point c){
    Point u=a-b,v=a-c;
    double m1=(norm(a)-norm(b))/2.0,m2=(norm(a)-norm(c))/2.0;
    
    Point res;
    if(cross(u,v)==0.0){
        res.x=1e9;
        res.y=1e9;
        
        return res;
    }
    res.x=(m1*v.y-m2*u.y)/cross(u,v);
    res.y=(m1*v.x-m2*u.x)/cross(v,u);
    
    return res;
}
//3点を通る円の中心を返す

//交わる 0
// c1がc2のinside 1
// c1がc2のoutside 2
// 交わらない 3

int not_intersect(Circle c1,Circle c2){
    double d=getDistance(c1.c,c2.c);
    double r1=c1.r,r2=c2.r;
    if(r1<r2){
        if(d<(r2-r1)) return 1;
    }
    if(r1>r2){
        if(d<(r1-r2)) return 2;
    }
    if(d<=r1+r2) return 0;
    else return 3;
}

pair<Point,Point> segCrossPpoints(Circle c,Line l){
    //assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    return make_pair(pr+e*base,pr-e*base);
}

double arg(Vector p){return atan2(p.y,p.x);}
Vector polar(double a,double r){return Point(cos(r)*a,sin(r)*a);}

//inside(outside)

pair<Point,Point> getCrossPoints(Circle c1,Circle c2){
    //assert(intersect(c1,c2));
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}

vector<Line> Commontangent(Circle c1,Circle c2){
    vector<Line> res;
    Point p=c2.c-c1.c;
    
    if(abs(p)>=(c1.r+c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r+c2.r)+p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r+c2.r)-p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r+c2.r)-p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r+c2.r)+p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    if(abs(p)>=abs(c1.r-c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r-c2.r)+p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r-c2.r)-p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r-c2.r)-p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r-c2.r)+p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    return res;
}

typedef vector<Point> Polygon;

/*
 IN 2
 ON 1
 OUT 0
 */

int contains(Polygon g,Point p){
    int n=int(g.size());
    bool x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(a.y>b.y) swap(a,b);
        if(a.y<eps&&0<b.y&&cross(a,b)<0) x=!x;
        if(abs(cross(a,b))<eps&&dot(a,b)<eps) return 1;
    }
    return (x?2:0);
}

Polygon andrewScan(Polygon s,bool ok){
    Polygon u,l;
    sort(all(s));
    
    if(int(s.size())<3) return s;
    int n=int(s.size());
    
    u.push_back(s[0]);
    u.push_back(s[1]);
    
    l.push_back(s[n-1]);
    l.push_back(s[n-2]);
    
    if(ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])==counter_clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])==counter_clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    if(!ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])!=clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])!=clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    reverse(all(l));
    
    for(int i=int(u.size())-2;i>=1;i--) l.push_back(u[i]);
    
    return l;
}//ok==1なら辺の上も含める

Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon Q;
    for(int i=0;i<si(P);i++){
        Point A=P[i],B=P[(i+1)%si(P)];
        if(ccw(l.p1,l.p2,A)!=-1)Q.push_back(A);
        if(ccw(l.p1,l.p2,A)*ccw(l.p1,l.p2,B)<0) Q.push_back(getCrossPointL(Line{A,B},l));
    }
    return Q;
}

double area(Point a,Point b,Point c){
    b=b-a;
    c=c-a;
    return abs(b.x*c.y-b.y*c.x)/2.0;
}

/*
 
 ll area(Polygon P){
 ll sum=0;
 for(int i=0;i<si(P);i++){
 sum+=cross(P[i],P[(i+1)%si(P)]);
 }
 return abs(sum);
 }
 
 */

// 倍

double area(Polygon &P){
    if(si(P)==0) return 0.0;
    double res=0;
    Point c={0.0,0.0};
    for(int i=0;i<si(P);i++){
        c=c+P[i];
    }
    c=c/si(P);
    
    for(int i=0;i<si(P);i++){
        res+=area(c,P[i],P[(i+1)%si(P)]);
    }
    
    return res;
}

ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}

pair<Point,Vector> perpendicular_bisector(Point a,Point b){
    Point c=(a+b)/2;
    Vector v=b-c;
    swap(v.x,v.y);
    v.x*=-1;
    
    Point p=c;
    if(v.x==0){
        v.y=1;
        p.y=0;
    }
    else if(v.y==0){
        v.x=1;
        p.x=0;
    }
    else{
        if(v.x<0){
            v.x*=-1;
            v.y*=-1;
        }
        ll g=gcd(abs(ll(v.x)),abs(ll(v.y)));
        v.x/=g;
        v.y/=g;
        if(p.x>=0){
            ll d=p.x/v.x;
            p=p-v*d;
        }else{
            ll d=abs(p.x)/v.x;
            p=p+v*d;
            
            if(p.x<0){
                p=p+v;
            }
        }
    }
    
    return mp(p,v);
}
//2倍するなりして整数にしておくこと

int N;
ll S[43];
int ans;

void solve(int u,int cn,ll mask){
    if(cn>=ans) return;
    if(u==N){
        if(mask==(1LL<<N)-1) chmin(ans,cn);
        return;
    }
    solve(u+1,cn+1,mask|S[u]);
    solve(u+1,cn,mask);
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    //cout<<fixed<<setprecision(10);
    
    cin>>N;
    vector<Point> P(N);
    for(int i=0;i<N;i++) cin>>P[i].x>>P[i].y;
    
    for(int a=0;a<N;a++){
        S[a]|=(1LL<<a);
        for(int b=a+1;b<N;b++){
            Segment s={P[a],P[b]};
            bool ok=true;
            if(a+1==b||(a==0&&b==N-1)){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                continue;
            }
            for(int i=0;i<N;i++){
                Segment t={P[i],P[(i+1)%N]};
                if(!intersect(s,t)) continue;
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<ccw(s.p1,s.p2,t.p1)<<" "<<ccw(s.p1,s.p2,t.p2)<<endl;
                //cout<<s.p1.x<<" "<<s.p1.y<<" "<<s.p2.x<<" "<<s.p2.y<<" "<<t.p2.x<<" "<<t.p2.y<<endl;
                if(ccw(s.p1,s.p2,t.p1)%2==0&&ccw(s.p1,s.p2,t.p2)%2==0) continue;
                Point p=getCrossPointS(s,t);
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<a<<" "<<b<<" "<<i<<" "<<p.x<<" "<<p.y<<endl;
                {
                    Point q=p-(P[b]-P[a])/abs(P[b]-P[a])*0.000001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(ccw(P[a],P[b],q)==0){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={q,{1100,q.y}};
                        else c={q,{q.x,1100}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
                {
                    Point q=p+(P[b]-P[a])/abs(P[b]-P[a])*0.000001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(ccw(P[a],P[b],q)==0){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={q,{1100,q.y}};
                        else c={q,{q.x,1100}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
            }
            if(ok){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                //cout<<a<<" "<<b<<endl;
            }
        }
    }
    
    ans=N;
    
    solve(0,0,0);
    
    cout<<ans<<endl;
}
accuracy: 0.1
time_ms: 740
memory_kb: 3468
final_rank: 11

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=3005,INF=1<<30;

#define double long double

//幾何ライブラリ
// define double ll をするときは Point の < と == も書き換えよう！

const double eps=1e-12;
const double pi=acos((double)-1.0L);
#define equals(a,b) (fabs((a)-(b))<eps)

double torad(double deg) {return (double)(deg)*pi/180.0;}
double todeg(double ang) {return ang*180.0/pi;}

class Point{
public:
    double x,y;
    
    Point(double x=0,double y=0):x(x),y(y){}
    
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double a){return Point(a*x,a*y);}
    Point operator / (double a){return Point(x/a,y/a);}
    
    double abs(){return sqrt(norm());}
    double norm(){return x*x+y*y;}
    
    bool operator < (const Point &p)const{
        return x+eps<p.x||(equals(x,p.x)&&y+eps<p.y);
        //return x<p.x||(x==p.x&&y<p.y);
    }
    
    bool operator == (const Point &p)const{
        return fabs(x-p.x)<eps/100000&&fabs(y-p.y)<eps/100000;
        //return x==p.x&&y==p.y;
    }
};

typedef Point Vector;

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

struct Segment{
    Point p1,p2;
};

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

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

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

Point turn(Point p,Point c,double pi){
    double q=atan2(p.y-c.y,p.x-c.x);
    q+=pi;
    p=c+Point{cos(q)*abs(p-c),sin(q)*abs(p-c)};
    
    return p;
}
//pをcを中心としてpi回転させる(1周で2π)
//p=cのときnan

//p0,p1,p2の順に見たときどうなるか？

static const int counter_clockwise=1;
static const int clockwise=-1;
static const int online_back=2;
static const int online_front=-2;
static const int on_segment=0;

int ccw(Point p0,Point p1,Point p2){
    Vector a=p1-p0;
    Vector b=p2-p0;
    
    if(cross(a,b)>eps) return counter_clockwise;
    if(cross(a,b)<-eps) return clockwise;
    if(dot(a,b)<-eps) return online_back;
    if(a.norm()<b.norm()) return online_front;
    
    return on_segment;
}

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

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

bool overlap(Segment s1,Segment s2){
    int a=ccw(s1.p1,s1.p2,s2.p1),b=ccw(s1.p1,s1.p2,s2.p2);
    if(a&1||b&1) return 0;
    if(a==2){
        if(b==-2||(b==0&&!(s2.p2==s1.p1))) return 1;
        else return 0;
    }
    if(a==-2){
        if(b==2||(b==0&&!(s2.p2==s1.p2))) return 1;
        else return 0;
    }
    if(a==0){
        if(s1.p1==s2.p1){
            if(b!=2) return 1;
            else return 0;
        }
        else if(s1.p2==s2.p1){
            if(b!=-2) return 1;
            else return 0;
        }
        else return 1;
    }
    return 0;
}
//s1とs2の共通の線分(長さ0より大きい)があるかどうか

typedef Segment Line;

double getDistance(Point a,Point b){
    return abs(a-b);
}

double getDistanceLP(Line l,Point p){
    return abs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1)<0.0) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2)<0.0) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistance(Segment s1,Segment s2){
    if(intersect(s1,s2)) return 0.0;
    return min({getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2),getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)});
}

Point getCrossPointS(Segment s1,Segment s2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}//同じ時壊れます

Point getCrossPointL(Line l1,Line l2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    
    return l1.p1+v1*cross(v2,l2.p1-l1.p1)/cross(v2,v1);
}

Segment ParallelSegment(Segment s,double d){
    Vector v={-(s.p2-s.p1).y,(s.p2-s.p1).x};
    v=v/abs(v);
    
    s.p1=s.p1+v*d;
    s.p2=s.p2+v*d;
    
    return s;
}

Point naisin(Point p1,Point p2,Point p3){
    if(p1==p2&&p2==p3&&p3==p1) return p1;
    
    return (p1*abs(p2-p3)+p2*abs(p1-p3)+p3*abs(p1-p2))/(abs(p2-p3)+abs(p1-p3)+abs(p1-p2));
}

Point naisin(Line l1,Line l2,Line l3){
    //平行でない前提
    
    Point p1=getCrossPointL(l1,l2),p2=getCrossPointL(l1,l3),p3=getCrossPointL(l2,l3);
    return naisin(p1,p2,p3);
}

//ネットの適当を書いたのであってるか全く知りません→あってそう

class Circle{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r){}
};

Point CircleCenter(Point a,Point b,Point c){
    Point u=a-b,v=a-c;
    double m1=(norm(a)-norm(b))/2.0,m2=(norm(a)-norm(c))/2.0;
    
    Point res;
    if(cross(u,v)==0.0){
        res.x=1e9;
        res.y=1e9;
        
        return res;
    }
    res.x=(m1*v.y-m2*u.y)/cross(u,v);
    res.y=(m1*v.x-m2*u.x)/cross(v,u);
    
    return res;
}
//3点を通る円の中心を返す

//交わる 0
// c1がc2のinside 1
// c1がc2のoutside 2
// 交わらない 3

int not_intersect(Circle c1,Circle c2){
    double d=getDistance(c1.c,c2.c);
    double r1=c1.r,r2=c2.r;
    if(r1<r2){
        if(d<(r2-r1)) return 1;
    }
    if(r1>r2){
        if(d<(r1-r2)) return 2;
    }
    if(d<=r1+r2) return 0;
    else return 3;
}

pair<Point,Point> segCrossPpoints(Circle c,Line l){
    //assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    return make_pair(pr+e*base,pr-e*base);
}

double arg(Vector p){return atan2(p.y,p.x);}
Vector polar(double a,double r){return Point(cos(r)*a,sin(r)*a);}

//inside(outside)

pair<Point,Point> getCrossPoints(Circle c1,Circle c2){
    //assert(intersect(c1,c2));
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}

vector<Line> Commontangent(Circle c1,Circle c2){
    vector<Line> res;
    Point p=c2.c-c1.c;
    
    if(abs(p)>=(c1.r+c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r+c2.r)+p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r+c2.r)-p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r+c2.r)-p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r+c2.r)+p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    if(abs(p)>=abs(c1.r-c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r-c2.r)+p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r-c2.r)-p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r-c2.r)-p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r-c2.r)+p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    return res;
}

typedef vector<Point> Polygon;

/*
 IN 2
 ON 1
 OUT 0
 */

int contains(Polygon g,Point p){
    int n=int(g.size());
    bool x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(a.y>b.y) swap(a,b);
        if(a.y<eps&&0<b.y&&cross(a,b)<0) x=!x;
        if(abs(cross(a,b))<eps&&dot(a,b)<eps) return 1;
    }
    return (x?2:0);
}

Polygon andrewScan(Polygon s,bool ok){
    Polygon u,l;
    sort(all(s));
    
    if(int(s.size())<3) return s;
    int n=int(s.size());
    
    u.push_back(s[0]);
    u.push_back(s[1]);
    
    l.push_back(s[n-1]);
    l.push_back(s[n-2]);
    
    if(ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])==counter_clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])==counter_clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    if(!ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])!=clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])!=clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    reverse(all(l));
    
    for(int i=int(u.size())-2;i>=1;i--) l.push_back(u[i]);
    
    return l;
}//ok==1なら辺の上も含める

Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon Q;
    for(int i=0;i<si(P);i++){
        Point A=P[i],B=P[(i+1)%si(P)];
        if(ccw(l.p1,l.p2,A)!=-1)Q.push_back(A);
        if(ccw(l.p1,l.p2,A)*ccw(l.p1,l.p2,B)<0) Q.push_back(getCrossPointL(Line{A,B},l));
    }
    return Q;
}

double area(Point a,Point b,Point c){
    b=b-a;
    c=c-a;
    return abs(b.x*c.y-b.y*c.x)/2.0;
}

/*
 
 ll area(Polygon P){
 ll sum=0;
 for(int i=0;i<si(P);i++){
 sum+=cross(P[i],P[(i+1)%si(P)]);
 }
 return abs(sum);
 }
 
 */

// 倍

double area(Polygon &P){
    if(si(P)==0) return 0.0;
    double res=0;
    Point c={0.0,0.0};
    for(int i=0;i<si(P);i++){
        c=c+P[i];
    }
    c=c/si(P);
    
    for(int i=0;i<si(P);i++){
        res+=area(c,P[i],P[(i+1)%si(P)]);
    }
    
    return res;
}

ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}

pair<Point,Vector> perpendicular_bisector(Point a,Point b){
    Point c=(a+b)/2;
    Vector v=b-c;
    swap(v.x,v.y);
    v.x*=-1;
    
    Point p=c;
    if(v.x==0){
        v.y=1;
        p.y=0;
    }
    else if(v.y==0){
        v.x=1;
        p.x=0;
    }
    else{
        if(v.x<0){
            v.x*=-1;
            v.y*=-1;
        }
        ll g=gcd(abs(ll(v.x)),abs(ll(v.y)));
        v.x/=g;
        v.y/=g;
        if(p.x>=0){
            ll d=p.x/v.x;
            p=p-v*d;
        }else{
            ll d=abs(p.x)/v.x;
            p=p+v*d;
            
            if(p.x<0){
                p=p+v;
            }
        }
    }
    
    return mp(p,v);
}
//2倍するなりして整数にしておくこと

int N;
ll S[43];
int ans;

void solve(int u,int cn,ll mask){
    if(cn>=ans) return;
    if(u==N){
        if(mask==(1LL<<N)-1) chmin(ans,cn);
        return;
    }
    solve(u+1,cn+1,mask|S[u]);
    solve(u+1,cn,mask);
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    //cout<<fixed<<setprecision(10);
    
    cin>>N;
    vector<Point> P(N);
    for(int i=0;i<N;i++) cin>>P[i].x>>P[i].y;
    
    for(int a=0;a<N;a++){
        S[a]|=(1LL<<a);
        for(int b=a+1;b<N;b++){
            Segment s={P[a],P[b]};
            bool ok=true;
            if(a+1==b||(a==0&&b==N-1)){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                continue;
            }
            for(int i=0;i<N;i++){
                Segment t={P[i],P[(i+1)%N]};
                if(!intersect(s,t)) continue;
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<ccw(s.p1,s.p2,t.p1)<<" "<<ccw(s.p1,s.p2,t.p2)<<endl;
                //cout<<s.p1.x<<" "<<s.p1.y<<" "<<s.p2.x<<" "<<s.p2.y<<" "<<t.p2.x<<" "<<t.p2.y<<endl;
                if(ccw(s.p1,s.p2,t.p1)%2==0&&ccw(s.p1,s.p2,t.p2)%2==0) continue;
                Point p=getCrossPointS(s,t);
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<a<<" "<<b<<" "<<i<<" "<<p.x<<" "<<p.y<<endl;
                {
                    Point q=p-(P[b]-P[a])/abs(P[b]-P[a])*0.000001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(getDistance(P[a],q)+getDistance(q,P[b])<=getDistance(P[a],P[b])){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={q,{1100,q.y}};
                        else c={q,{q.x,1100}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
                {
                    Point q=p+(P[b]-P[a])/abs(P[b]-P[a])*0.000001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(getDistance(P[a],q)+getDistance(q,P[b])<=getDistance(P[a],P[b])){
                        bool f=false;
                        Segment c;
                        if(P[a].x==P[b].x) c={q,{1100,q.y}};
                        else c={q,{q.x,1100}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
            }
            if(ok){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                //cout<<a<<" "<<b<<endl;
            }
        }
    }
    
    ans=N;
    
    solve(0,0,0);
    
    cout<<ans<<endl;
}
accuracy: 0.04
time_ms: 130
memory_kb: 3544
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=3005,INF=1<<30;

//幾何ライブラリ
// define double ll をするときは Point の < と == も書き換えよう！

const double eps=1e-8;
const double pi=acos((double)-1.0L);
#define equals(a,b) (fabs((a)-(b))<eps)

double torad(double deg) {return (double)(deg)*pi/180.0;}
double todeg(double ang) {return ang*180.0/pi;}

class Point{
public:
    double x,y;
    
    Point(double x=0,double y=0):x(x),y(y){}
    
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double a){return Point(a*x,a*y);}
    Point operator / (double a){return Point(x/a,y/a);}
    
    double abs(){return sqrt(norm());}
    double norm(){return x*x+y*y;}
    
    bool operator < (const Point &p)const{
        return x+eps<p.x||(equals(x,p.x)&&y+eps<p.y);
        //return x<p.x||(x==p.x&&y<p.y);
    }
    
    bool operator == (const Point &p)const{
        return fabs(x-p.x)<eps/100000&&fabs(y-p.y)<eps/100000;
        //return x==p.x&&y==p.y;
    }
};

typedef Point Vector;

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

struct Segment{
    Point p1,p2;
};

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

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

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

Point turn(Point p,Point c,double pi){
    double q=atan2(p.y-c.y,p.x-c.x);
    q+=pi;
    p=c+Point{cos(q)*abs(p-c),sin(q)*abs(p-c)};
    
    return p;
}
//pをcを中心としてpi回転させる(1周で2π)
//p=cのときnan

//p0,p1,p2の順に見たときどうなるか？

static const int counter_clockwise=1;
static const int clockwise=-1;
static const int online_back=2;
static const int online_front=-2;
static const int on_segment=0;

int ccw(Point p0,Point p1,Point p2){
    Vector a=p1-p0;
    Vector b=p2-p0;
    
    if(cross(a,b)>eps) return counter_clockwise;
    if(cross(a,b)<-eps) return clockwise;
    if(dot(a,b)<-eps) return online_back;
    if(a.norm()<b.norm()) return online_front;
    
    return on_segment;
}

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

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

bool overlap(Segment s1,Segment s2){
    int a=ccw(s1.p1,s1.p2,s2.p1),b=ccw(s1.p1,s1.p2,s2.p2);
    if(a&1||b&1) return 0;
    if(a==2){
        if(b==-2||(b==0&&!(s2.p2==s1.p1))) return 1;
        else return 0;
    }
    if(a==-2){
        if(b==2||(b==0&&!(s2.p2==s1.p2))) return 1;
        else return 0;
    }
    if(a==0){
        if(s1.p1==s2.p1){
            if(b!=2) return 1;
            else return 0;
        }
        else if(s1.p2==s2.p1){
            if(b!=-2) return 1;
            else return 0;
        }
        else return 1;
    }
    return 0;
}
//s1とs2の共通の線分(長さ0より大きい)があるかどうか

typedef Segment Line;

double getDistance(Point a,Point b){
    return abs(a-b);
}

double getDistanceLP(Line l,Point p){
    return abs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1)<0.0) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2)<0.0) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistance(Segment s1,Segment s2){
    if(intersect(s1,s2)) return 0.0;
    return min({getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2),getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)});
}

Point getCrossPointS(Segment s1,Segment s2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}//同じ時壊れます

Point getCrossPointL(Line l1,Line l2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    
    return l1.p1+v1*cross(v2,l2.p1-l1.p1)/cross(v2,v1);
}

Segment ParallelSegment(Segment s,double d){
    Vector v={-(s.p2-s.p1).y,(s.p2-s.p1).x};
    v=v/abs(v);
    
    s.p1=s.p1+v*d;
    s.p2=s.p2+v*d;
    
    return s;
}

Point naisin(Point p1,Point p2,Point p3){
    if(p1==p2&&p2==p3&&p3==p1) return p1;
    
    return (p1*abs(p2-p3)+p2*abs(p1-p3)+p3*abs(p1-p2))/(abs(p2-p3)+abs(p1-p3)+abs(p1-p2));
}

Point naisin(Line l1,Line l2,Line l3){
    //平行でない前提
    
    Point p1=getCrossPointL(l1,l2),p2=getCrossPointL(l1,l3),p3=getCrossPointL(l2,l3);
    return naisin(p1,p2,p3);
}

//ネットの適当を書いたのであってるか全く知りません→あってそう

class Circle{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r){}
};

Point CircleCenter(Point a,Point b,Point c){
    Point u=a-b,v=a-c;
    double m1=(norm(a)-norm(b))/2.0,m2=(norm(a)-norm(c))/2.0;
    
    Point res;
    if(cross(u,v)==0.0){
        res.x=1e9;
        res.y=1e9;
        
        return res;
    }
    res.x=(m1*v.y-m2*u.y)/cross(u,v);
    res.y=(m1*v.x-m2*u.x)/cross(v,u);
    
    return res;
}
//3点を通る円の中心を返す

//交わる 0
// c1がc2のinside 1
// c1がc2のoutside 2
// 交わらない 3

int not_intersect(Circle c1,Circle c2){
    double d=getDistance(c1.c,c2.c);
    double r1=c1.r,r2=c2.r;
    if(r1<r2){
        if(d<(r2-r1)) return 1;
    }
    if(r1>r2){
        if(d<(r1-r2)) return 2;
    }
    if(d<=r1+r2) return 0;
    else return 3;
}

pair<Point,Point> segCrossPpoints(Circle c,Line l){
    //assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    return make_pair(pr+e*base,pr-e*base);
}

double arg(Vector p){return atan2(p.y,p.x);}
Vector polar(double a,double r){return Point(cos(r)*a,sin(r)*a);}

//inside(outside)

pair<Point,Point> getCrossPoints(Circle c1,Circle c2){
    //assert(intersect(c1,c2));
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}

vector<Line> Commontangent(Circle c1,Circle c2){
    vector<Line> res;
    Point p=c2.c-c1.c;
    
    if(abs(p)>=(c1.r+c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r+c2.r)+p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r+c2.r)-p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r+c2.r)-p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r+c2.r)+p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    if(abs(p)>=abs(c1.r-c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r-c2.r)+p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r-c2.r)-p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r-c2.r)-p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r-c2.r)+p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    return res;
}

typedef vector<Point> Polygon;

/*
 IN 2
 ON 1
 OUT 0
 */

int contains(Polygon g,Point p){
    int n=int(g.size());
    bool x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(a.y>b.y) swap(a,b);
        if(a.y<eps&&0<b.y&&cross(a,b)<0) x=!x;
        if(abs(cross(a,b))<eps&&dot(a,b)<eps) return 1;
    }
    return (x?2:0);
}

Polygon andrewScan(Polygon s,bool ok){
    Polygon u,l;
    sort(all(s));
    
    if(int(s.size())<3) return s;
    int n=int(s.size());
    
    u.push_back(s[0]);
    u.push_back(s[1]);
    
    l.push_back(s[n-1]);
    l.push_back(s[n-2]);
    
    if(ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])==counter_clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])==counter_clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    if(!ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])!=clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])!=clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    reverse(all(l));
    
    for(int i=int(u.size())-2;i>=1;i--) l.push_back(u[i]);
    
    return l;
}//ok==1なら辺の上も含める

Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon Q;
    for(int i=0;i<si(P);i++){
        Point A=P[i],B=P[(i+1)%si(P)];
        if(ccw(l.p1,l.p2,A)!=-1)Q.push_back(A);
        if(ccw(l.p1,l.p2,A)*ccw(l.p1,l.p2,B)<0) Q.push_back(getCrossPointL(Line{A,B},l));
    }
    return Q;
}

double area(Point a,Point b,Point c){
    b=b-a;
    c=c-a;
    return abs(b.x*c.y-b.y*c.x)/2.0;
}

/*
 
 ll area(Polygon P){
 ll sum=0;
 for(int i=0;i<si(P);i++){
 sum+=cross(P[i],P[(i+1)%si(P)]);
 }
 return abs(sum);
 }
 
 */

// 倍

double area(Polygon &P){
    if(si(P)==0) return 0.0;
    double res=0;
    Point c={0.0,0.0};
    for(int i=0;i<si(P);i++){
        c=c+P[i];
    }
    c=c/si(P);
    
    for(int i=0;i<si(P);i++){
        res+=area(c,P[i],P[(i+1)%si(P)]);
    }
    
    return res;
}

ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}

pair<Point,Vector> perpendicular_bisector(Point a,Point b){
    Point c=(a+b)/2;
    Vector v=b-c;
    swap(v.x,v.y);
    v.x*=-1;
    
    Point p=c;
    if(v.x==0){
        v.y=1;
        p.y=0;
    }
    else if(v.y==0){
        v.x=1;
        p.x=0;
    }
    else{
        if(v.x<0){
            v.x*=-1;
            v.y*=-1;
        }
        ll g=gcd(abs(ll(v.x)),abs(ll(v.y)));
        v.x/=g;
        v.y/=g;
        if(p.x>=0){
            ll d=p.x/v.x;
            p=p-v*d;
        }else{
            ll d=abs(p.x)/v.x;
            p=p+v*d;
            
            if(p.x<0){
                p=p+v;
            }
        }
    }
    
    return mp(p,v);
}
//2倍するなりして整数にしておくこと

int N;
ll S[43];
int ans;

void solve(int u,int cn,ll mask){
    if(cn>=ans) return;
    if(u==N){
        if(mask==(1LL<<N)-1) chmin(ans,cn);
        return;
    }
    solve(u+1,cn+1,mask|S[u]);
    solve(u+1,cn,mask);
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    //cout<<fixed<<setprecision(10);
    
    cin>>N;
    vector<Point> P(N);
    for(int i=0;i<N;i++) cin>>P[i].x>>P[i].y;
    
    for(int a=0;a<N;a++){
        S[a]|=(1LL<<a);
        for(int b=a+1;b<N;b++){
            Segment s={P[a],P[b]};
            bool ok=true;
            for(int i=0;i<N;i++){
                Segment t={P[i],P[(i+1)%N]};
                if(!intersect(s,t)) continue;
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<ccw(s.p1,s.p2,t.p1)<<" "<<ccw(s.p1,s.p2,t.p2)<<endl;
                //cout<<s.p1.x<<" "<<s.p1.y<<" "<<s.p2.x<<" "<<s.p2.y<<" "<<t.p2.x<<" "<<t.p2.y<<endl;
                if(ccw(s.p1,s.p2,t.p1)%2==0&&ccw(s.p1,s.p2,t.p2)%2==0) continue;
                Point p=getCrossPointS(s,t);
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<a<<" "<<b<<" "<<i<<" "<<p.x<<" "<<p.y<<endl;
                {
                    Point q=p-(P[b]-P[a])/abs(P[b]-P[a])*0.000005;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(getDistance(P[a],q)+getDistance(q,P[b])==getDistance(P[a],P[b])){
                        bool f=false;
                        Segment c={q,{q.x,1100}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
                {
                    Point q=p+(P[b]-P[a])/abs(P[b]-P[a])*0.000005;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(getDistance(P[a],q)+getDistance(q,P[b])==getDistance(P[a],P[b])){
                        bool f=false;
                        Segment c={q,{q.x,1100}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
            }
            if(ok){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                //cout<<a<<" "<<b<<endl;
            }
        }
    }
    
    ans=N;
    
    solve(0,0,0);
    
    cout<<ans<<endl;
}
accuracy: 0.06
time_ms: 440
memory_kb: 3528
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=998244353,MAX=3005,INF=1<<30;

//幾何ライブラリ
// define double ll をするときは Point の < と == も書き換えよう！

const double eps=1e-8;
const double pi=acos((double)-1.0L);
#define equals(a,b) (fabs((a)-(b))<eps)

double torad(double deg) {return (double)(deg)*pi/180.0;}
double todeg(double ang) {return ang*180.0/pi;}

class Point{
public:
    double x,y;
    
    Point(double x=0,double y=0):x(x),y(y){}
    
    Point operator + (Point p){return Point(x+p.x,y+p.y);}
    Point operator - (Point p){return Point(x-p.x,y-p.y);}
    Point operator * (double a){return Point(a*x,a*y);}
    Point operator / (double a){return Point(x/a,y/a);}
    
    double abs(){return sqrt(norm());}
    double norm(){return x*x+y*y;}
    
    bool operator < (const Point &p)const{
        return x+eps<p.x||(equals(x,p.x)&&y+eps<p.y);
        //return x<p.x||(x==p.x&&y<p.y);
    }
    
    bool operator == (const Point &p)const{
        return fabs(x-p.x)<eps/100000&&fabs(y-p.y)<eps/100000;
        //return x==p.x&&y==p.y;
    }
};

typedef Point Vector;

double norm(Vector a){
    return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
    return sqrt(norm(a));
}

double dot(Vector a,Vector b){
    return a.x*b.x+a.y*b.y;
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

struct Segment{
    Point p1,p2;
};

bool isOrthogonal(Vector a,Vector b){
    return equals(dot(a,b),0.0);
}

bool isOrthogonal(Point a1,Point a2,Point b1,Point b2){
    return isOrthogonal(a1-a2,b1-b2);
}

bool isOrthogonal(Segment s1,Segment s2){
    return equals(dot(s1.p2-s1.p1,s2.p2-s2.p1),0.0);
}

bool isParallel(Vector a,Vector b){
    return equals(cross(a,b),0.0);
}

bool isParallel(Point a1,Point a2,Point b1,Point b2){
    return isParallel(a1-a2,b1-b2);
}

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

Point project(Segment s,Point p){
    Vector base=s.p2-s.p1;
    double r=dot(p-s.p1,base)/norm(base);
    return s.p1+base*r;
}

Point reflect(Segment s,Point p){
    return p+(project(s,p)-p)*2.0;
}

Point turn(Point p,Point c,double pi){
    double q=atan2(p.y-c.y,p.x-c.x);
    q+=pi;
    p=c+Point{cos(q)*abs(p-c),sin(q)*abs(p-c)};
    
    return p;
}
//pをcを中心としてpi回転させる(1周で2π)
//p=cのときnan

//p0,p1,p2の順に見たときどうなるか？

static const int counter_clockwise=1;
static const int clockwise=-1;
static const int online_back=2;
static const int online_front=-2;
static const int on_segment=0;

int ccw(Point p0,Point p1,Point p2){
    Vector a=p1-p0;
    Vector b=p2-p0;
    
    if(cross(a,b)>eps) return counter_clockwise;
    if(cross(a,b)<-eps) return clockwise;
    if(dot(a,b)<-eps) return online_back;
    if(a.norm()<b.norm()) return online_front;
    
    return on_segment;
}

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

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

bool overlap(Segment s1,Segment s2){
    int a=ccw(s1.p1,s1.p2,s2.p1),b=ccw(s1.p1,s1.p2,s2.p2);
    if(a&1||b&1) return 0;
    if(a==2){
        if(b==-2||(b==0&&!(s2.p2==s1.p1))) return 1;
        else return 0;
    }
    if(a==-2){
        if(b==2||(b==0&&!(s2.p2==s1.p2))) return 1;
        else return 0;
    }
    if(a==0){
        if(s1.p1==s2.p1){
            if(b!=2) return 1;
            else return 0;
        }
        else if(s1.p2==s2.p1){
            if(b!=-2) return 1;
            else return 0;
        }
        else return 1;
    }
    return 0;
}
//s1とs2の共通の線分(長さ0より大きい)があるかどうか

typedef Segment Line;

double getDistance(Point a,Point b){
    return abs(a-b);
}

double getDistanceLP(Line l,Point p){
    return abs(cross(l.p2-l.p1,p-l.p1)/abs(l.p2-l.p1));
}

double getDistanceSP(Segment s,Point p){
    if(dot(s.p2-s.p1,p-s.p1)<0.0) return abs(p-s.p1);
    if(dot(s.p1-s.p2,p-s.p2)<0.0) return abs(p-s.p2);
    return getDistanceLP(s,p);
}

double getDistance(Segment s1,Segment s2){
    if(intersect(s1,s2)) return 0.0;
    return min({getDistanceSP(s1,s2.p1),getDistanceSP(s1,s2.p2),getDistanceSP(s2,s1.p1),getDistanceSP(s2,s1.p2)});
}

Point getCrossPointS(Segment s1,Segment s2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    Vector base=s2.p2-s2.p1;
    double d1=abs(cross(base,s1.p1-s2.p1));
    double d2=abs(cross(base,s1.p2-s2.p1));
    double t=d1/(d1+d2);
    return s1.p1+(s1.p2-s1.p1)*t;
}//同じ時壊れます

Point getCrossPointL(Line l1,Line l2){
    //if(ccw(s1.p1,s1.p2,s2.p1)==0&&ccw(s1.p1,s1.p2,s2.p2)==0) return s1.p1;
    
    Vector v1=l1.p2-l1.p1,v2=l2.p2-l2.p1;
    
    return l1.p1+v1*cross(v2,l2.p1-l1.p1)/cross(v2,v1);
}

Segment ParallelSegment(Segment s,double d){
    Vector v={-(s.p2-s.p1).y,(s.p2-s.p1).x};
    v=v/abs(v);
    
    s.p1=s.p1+v*d;
    s.p2=s.p2+v*d;
    
    return s;
}

Point naisin(Point p1,Point p2,Point p3){
    if(p1==p2&&p2==p3&&p3==p1) return p1;
    
    return (p1*abs(p2-p3)+p2*abs(p1-p3)+p3*abs(p1-p2))/(abs(p2-p3)+abs(p1-p3)+abs(p1-p2));
}

Point naisin(Line l1,Line l2,Line l3){
    //平行でない前提
    
    Point p1=getCrossPointL(l1,l2),p2=getCrossPointL(l1,l3),p3=getCrossPointL(l2,l3);
    return naisin(p1,p2,p3);
}

//ネットの適当を書いたのであってるか全く知りません→あってそう

class Circle{
public:
    Point c;
    double r;
    Circle(Point c=Point(),double r=0.0):c(c),r(r){}
};

Point CircleCenter(Point a,Point b,Point c){
    Point u=a-b,v=a-c;
    double m1=(norm(a)-norm(b))/2.0,m2=(norm(a)-norm(c))/2.0;
    
    Point res;
    if(cross(u,v)==0.0){
        res.x=1e9;
        res.y=1e9;
        
        return res;
    }
    res.x=(m1*v.y-m2*u.y)/cross(u,v);
    res.y=(m1*v.x-m2*u.x)/cross(v,u);
    
    return res;
}
//3点を通る円の中心を返す

//交わる 0
// c1がc2のinside 1
// c1がc2のoutside 2
// 交わらない 3

int not_intersect(Circle c1,Circle c2){
    double d=getDistance(c1.c,c2.c);
    double r1=c1.r,r2=c2.r;
    if(r1<r2){
        if(d<(r2-r1)) return 1;
    }
    if(r1>r2){
        if(d<(r1-r2)) return 2;
    }
    if(d<=r1+r2) return 0;
    else return 3;
}

pair<Point,Point> segCrossPpoints(Circle c,Line l){
    //assert(intersect(c,l));
    Vector pr=project(l,c.c);
    Vector e=(l.p2-l.p1)/abs(l.p2-l.p1);
    double base=sqrt(c.r*c.r-norm(pr-c.c));
    return make_pair(pr+e*base,pr-e*base);
}

double arg(Vector p){return atan2(p.y,p.x);}
Vector polar(double a,double r){return Point(cos(r)*a,sin(r)*a);}

//inside(outside)

pair<Point,Point> getCrossPoints(Circle c1,Circle c2){
    //assert(intersect(c1,c2));
    double d=abs(c1.c-c2.c);
    double a=acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
    double t=arg(c2.c-c1.c);
    return make_pair(c1.c+polar(c1.r,t+a),c1.c+polar(c1.r,t-a));
}

vector<Line> Commontangent(Circle c1,Circle c2){
    vector<Line> res;
    Point p=c2.c-c1.c;
    
    if(abs(p)>=(c1.r+c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r+c2.r)+p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r+c2.r)-p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r+c2.r)-p.y*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r+c2.r)+p.x*sqrt(norm(p)-(c1.r+c2.r)*(c1.r+c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    if(abs(p)>=abs(c1.r-c2.r)){
        Point a,b;
        a.x=c1.r*(p.x*(c1.r-c2.r)+p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        a.y=c1.r*(p.y*(c1.r-c2.r)-p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        b.x=c1.r*(p.x*(c1.r-c2.r)-p.y*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        b.y=c1.r*(p.y*(c1.r-c2.r)+p.x*sqrt(norm(p)-(c1.r-c2.r)*(c1.r-c2.r)))/norm(p);
        
        res.push_back(Line{a+c1.c,a+c1.c+Point{-a.y,a.x}});
        if(!(a==b)){
            res.push_back(Line{b+c1.c,b+c1.c+Point{-b.y,b.x}});
        }
    }
    
    return res;
}

typedef vector<Point> Polygon;

/*
 IN 2
 ON 1
 OUT 0
 */

int contains(Polygon g,Point p){
    int n=int(g.size());
    bool x=false;
    for(int i=0;i<n;i++){
        Point a=g[i]-p,b=g[(i+1)%n]-p;
        if(a.y>b.y) swap(a,b);
        if(a.y<eps&&0<b.y&&cross(a,b)<0) x=!x;
        if(abs(cross(a,b))<eps&&dot(a,b)<eps) return 1;
    }
    return (x?2:0);
}

Polygon andrewScan(Polygon s,bool ok){
    Polygon u,l;
    sort(all(s));
    
    if(int(s.size())<3) return s;
    int n=int(s.size());
    
    u.push_back(s[0]);
    u.push_back(s[1]);
    
    l.push_back(s[n-1]);
    l.push_back(s[n-2]);
    
    if(ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])==counter_clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])==counter_clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    if(!ok){
        for(int i=2;i<n;i++){
            for(int j=int(u.size());j>=2&&ccw(u[j-2],u[j-1],s[i])!=clockwise;j--){
                u.pop_back();
            }
            u.push_back(s[i]);
        }
        
        for(int i=int(s.size())-3;i>=0;i--){
            for(int j=int(l.size());j>=2&&ccw(l[j-2],l[j-1],s[i])!=clockwise;j--){
                l.pop_back();
            }
            l.push_back(s[i]);
        }
    }
    
    reverse(all(l));
    
    for(int i=int(u.size())-2;i>=1;i--) l.push_back(u[i]);
    
    return l;
}//ok==1なら辺の上も含める

Polygon convex_cut(const Polygon& P, const Line& l) {
    Polygon Q;
    for(int i=0;i<si(P);i++){
        Point A=P[i],B=P[(i+1)%si(P)];
        if(ccw(l.p1,l.p2,A)!=-1)Q.push_back(A);
        if(ccw(l.p1,l.p2,A)*ccw(l.p1,l.p2,B)<0) Q.push_back(getCrossPointL(Line{A,B},l));
    }
    return Q;
}

double area(Point a,Point b,Point c){
    b=b-a;
    c=c-a;
    return abs(b.x*c.y-b.y*c.x)/2.0;
}

/*
 
 ll area(Polygon P){
 ll sum=0;
 for(int i=0;i<si(P);i++){
 sum+=cross(P[i],P[(i+1)%si(P)]);
 }
 return abs(sum);
 }
 
 */

// 倍

double area(Polygon &P){
    if(si(P)==0) return 0.0;
    double res=0;
    Point c={0.0,0.0};
    for(int i=0;i<si(P);i++){
        c=c+P[i];
    }
    c=c/si(P);
    
    for(int i=0;i<si(P);i++){
        res+=area(c,P[i],P[(i+1)%si(P)]);
    }
    
    return res;
}

ll gcd(ll a,ll b){
    if(b==0) return a;
    return gcd(b,a%b);
}

pair<Point,Vector> perpendicular_bisector(Point a,Point b){
    Point c=(a+b)/2;
    Vector v=b-c;
    swap(v.x,v.y);
    v.x*=-1;
    
    Point p=c;
    if(v.x==0){
        v.y=1;
        p.y=0;
    }
    else if(v.y==0){
        v.x=1;
        p.x=0;
    }
    else{
        if(v.x<0){
            v.x*=-1;
            v.y*=-1;
        }
        ll g=gcd(abs(ll(v.x)),abs(ll(v.y)));
        v.x/=g;
        v.y/=g;
        if(p.x>=0){
            ll d=p.x/v.x;
            p=p-v*d;
        }else{
            ll d=abs(p.x)/v.x;
            p=p+v*d;
            
            if(p.x<0){
                p=p+v;
            }
        }
    }
    
    return mp(p,v);
}
//2倍するなりして整数にしておくこと

int N;
ll S[43];
int ans;

void solve(int u,int cn,ll mask){
    if(cn>=ans) return;
    if(u==N){
        if(mask==(1LL<<N)-1) chmin(ans,cn);
        return;
    }
    solve(u+1,cn+1,mask|S[u]);
    solve(u+1,cn,mask);
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    //cout<<fixed<<setprecision(10);
    
    cin>>N;
    vector<Point> P(N);
    for(int i=0;i<N;i++) cin>>P[i].x>>P[i].y;
    
    for(int a=0;a<N;a++){
        S[a]|=(1LL<<a);
        for(int b=a+1;b<N;b++){
            Segment s={P[a],P[b]};
            bool ok=true;
            for(int i=0;i<N;i++){
                Segment t={P[i],P[(i+1)%N]};
                if(!intersect(s,t)) continue;
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<ccw(s.p1,s.p2,t.p1)<<" "<<ccw(s.p1,s.p2,t.p2)<<endl;
                //cout<<s.p1.x<<" "<<s.p1.y<<" "<<s.p2.x<<" "<<s.p2.y<<" "<<t.p2.x<<" "<<t.p2.y<<endl;
                if(ccw(s.p1,s.p2,t.p1)%2==0&&ccw(s.p1,s.p2,t.p2)%2==0) continue;
                Point p=getCrossPointS(s,t);
                //cout<<a<<" "<<b<<" "<<i<<" "<<ok<<endl;
                //cout<<a<<" "<<b<<" "<<i<<" "<<p.x<<" "<<p.y<<endl;
                {
                    Point q=p-(P[b]-P[a])/abs(P[b]-P[a])*0.00001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(getDistance(P[a],q)+getDistance(q,P[b])==getDistance(P[a],P[b])){
                        bool f=false;
                        Segment c={q,{q.x,1100}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
                {
                    Point q=p+(P[b]-P[a])/abs(P[b]-P[a])*0.00001;
                    //cout<<q.x<<" "<<q.y<<endl;
                    if(getDistance(P[a],q)+getDistance(q,P[b])==getDistance(P[a],P[b])){
                        bool f=false;
                        Segment c={q,{q.x,1100}};
                        for(int j=0;j<N;j++){
                            Segment d={P[j],P[(j+1)%N]};
                            if(ccw(d.p1,d.p2,c.p1)==0) continue;
                            f^=intersect(c,d);
                        }
                        ok&=f;
                    }
                }
            }
            if(ok){
                S[a]|=(1LL<<b);
                S[b]|=(1LL<<a);
                //cout<<a<<" "<<b<<endl;
            }
        }
    }
    
    ans=N;
    
    solve(0,0,0);
    
    cout<<ans<<endl;
}
accuracy: 0.04
time_ms: 30
memory_kb: 3460
final_rank: 17

code_snippet: //#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

typedef complex<ld> Point;
ld dot(Point a, Point b) { return real(conj(a) * b); }
ld cross(Point a, Point b) { return imag(conj(a) * b); }
namespace std {
	bool operator<(const Point& lhs, const Point& rhs) {
		return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
	}
}
struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//counter clockwise
	if (cross(b, c) < -eps)return -1;//clock wise
	if (dot(b, c) < 0)return 2;//c--a--b on line
	if (norm(b) < norm(c))return -2;//a--b--c on line
	return 0; //a--c--b on line
}
bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
//2直線の交差判定
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
//直線と線分の交差判定
bool isis_ls(Line l, Line s) {
	return (cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}
//点が直線上に存在するか
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);
}
//線分と線分の交差判定2
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;
}
//点から直線への垂線の足
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);
}
//直線と直線の交点
//平行な２直線に対しては使うな！！！！
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<Point> is_ss(Line s1, Line s2) {
	if (!isis_ss(s1, s2))return {};
	vector<Point> res;
	if (abs(cross(s1.b - s1.a, s2.b - s2.a)) < eps) {
		if (isis_sp(s1, s2.a)) res.push_back(s2.a);
		if (isis_sp(s1, s2.b)) res.push_back(s2.b);
		if (isis_sp(s2, s1.a)) res.push_back(s1.a);
		if (isis_sp(s2, s1.b)) res.push_back(s1.b);
	}
	else {
		res.push_back(is_ll(s1, s2));
	}
	return res;

}
typedef vector<Point> polygon;

int is_in_polygon(polygon& poly, Point p) {
	ld sum = 0;
	int n = poly.size();
	rep(i,n) {
		int ni = i + 1 == n ? 0 : i + 1;
		Point pl = poly[i];
		Point pr = poly[ni];
		Line e = { pl,pr };
		if (isis_sp(e, p))return 0;
		sum += arg((pr - p) / (pl - p));
	}
	if (abs(sum) < pi / 2)return 2;
	return 1;
}
bool edge_in_polygon(polygon &poly,Line l) {
	Point s = l.a, t = l.b;
	if (is_in_polygon(poly, s) == 2 || is_in_polygon(poly, t) == 2)return false;
	vector<ld> ts;
	int n = poly.size();
	rep(i, n) {
		int ni = i + 1 == n ? 0 : i + 1;
		Point pl = poly[i];
		Point pr = poly[ni];
		Line e = { pl,pr };
		vector<Point> vp = is_ss(l, e);
		for (Point p : vp) {
			ld val = abs(p - s) / abs(t - s);
			ts.push_back(val);
		}
	}
	ts.push_back(0);
	ts.push_back(1);
	sort(all(ts));
	rep(i, ts.size() - 1) {
		ld x = (ts[i] + ts[i + 1]) / 2;
		Point c = s + (t - s) * x;
		if (is_in_polygon(poly, c) == 2)return false;
	}
	return true;
}



bool exi[40][40];
int n;
void solve() {
	cin >> n;
	vector<int> x(n), y(n);
	vector<Point> poly;
	rep(i, n)cin >> x[i] >> y[i];
	rep(i, n)poly.push_back({ (ld)x[i],(ld)y[i] });
	rep(i, n) {
		rep(j, n) {
			if (i == j)exi[i][j] = true;
			else {
				Point p = { (ld)x[i],(ld)y[i] };
				Point q = { (ld)x[j],(ld)y[j] };
				Line l = { p,q };
				exi[i][j] = edge_in_polygon(poly, l);
			}
		}
	}
	//rep(i, n) {
	//	rep(j, n)cout << exi[i][j];
	//	cout << "\n";
	//}
	vector<ll> ts;
	rep(i, n) {
		ll s = 0;
		rep(j, n)if(exi[i][j]) {
			s |= (1ll << j);
		}
		ts.push_back(s);
	}
	sort(all(ts));
	ts.erase(unique(all(ts)), ts.end());

	vector<ll> vs;
	rep(i, ts.size()) {
		//cout << ts[i] << "\n";
		bool exi = false;
		Rep(j, i + 1, ts.size()) {
			if ((ts[j] & ts[i]) == ts[i])exi = true;
		}
		if (!exi)vs.push_back(ts[i]);
	}
	int len = vs.size();
	int ans = n;
	set<ll> st[11];
	st[0].insert(0);
	rep(i, len) {
		for (int c = 9; c >= 0; c--) {
			for (ll val : st[c]) {
				ll nex = val | vs[i];
				st[c + 1].insert(nex);
			}
		}
	}
	rep(i, 11)if (st[i].count((1ll << n) - 1)) {
		ans=i;break;
	}
	cout << ans << "\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(8);
	init_f();
	//init();
	//int t; cin >> t; rep(i, t)
	//while (cin >> n, n)
		solve();
	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 21192
final_rank: 6

code_snippet: //#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

typedef complex<ld> Point;
ld dot(Point a, Point b) { return real(conj(a) * b); }
ld cross(Point a, Point b) { return imag(conj(a) * b); }
namespace std {
	bool operator<(const Point& lhs, const Point& rhs) {
		return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
	}
}
struct Line {
	Point a, b;
};
struct Circle {
	Point p; ld r;
};
int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//counter clockwise
	if (cross(b, c) < -eps)return -1;//clock wise
	if (dot(b, c) < 0)return 2;//c--a--b on line
	if (norm(b) < norm(c))return -2;//a--b--c on line
	return 0; //a--c--b on line
}
bool eq(ld a, ld b) {
	return abs(a - b) < eps;
}
//2直線の交差判定
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
//直線と線分の交差判定
bool isis_ls(Line l, Line s) {
	return (cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}
//点が直線上に存在するか
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);
}
//線分と線分の交差判定2
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;
}
//点から直線への垂線の足
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);
}
//直線と直線の交点
//平行な２直線に対しては使うな！！！！
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<Point> is_ss(Line s1, Line s2) {
	if (!isis_ss(s1, s2))return {};
	vector<Point> res;
	if (abs(cross(s1.b - s1.a, s2.b - s2.a)) < eps) {
		if (isis_sp(s1, s2.a)) res.push_back(s2.a);
		if (isis_sp(s1, s2.b)) res.push_back(s2.b);
		if (isis_sp(s2, s1.a)) res.push_back(s1.a);
		if (isis_sp(s2, s1.b)) res.push_back(s1.b);
	}
	else {
		res.push_back(is_ll(s1, s2));
	}
	return res;

}
typedef vector<Point> polygon;

int is_in_polygon(polygon& poly, Point p) {
	ld sum = 0;
	int n = poly.size();
	rep(i,n) {
		int ni = i + 1 == n ? 0 : i + 1;
		Point pl = poly[i];
		Point pr = poly[ni];
		Line e = { pl,pr };
		if (isis_sp(e, p))return 0;
		sum += arg((pr - p) / (pl - p));
	}
	if (abs(sum) < pi / 2)return 2;
	return 1;
}
bool edge_in_polygon(polygon &poly,Line l) {
	Point s = l.a, t = l.b;
	if (is_in_polygon(poly, s) == 2 || is_in_polygon(poly, t) == 2)return false;
	vector<ld> ts;
	int n = poly.size();
	rep(i, n) {
		int ni = i + 1 == n ? 0 : i + 1;
		Point pl = poly[i];
		Point pr = poly[ni];
		Line e = { pl,pr };
		vector<Point> vp = is_ss(l, e);
		for (Point p : vp) {
			ld val = abs(p - s) / abs(t - s);
			ts.push_back(val);
		}
	}
	ts.push_back(0);
	ts.push_back(1);
	sort(all(ts));
	rep(i, ts.size() - 1) {
		ld x = (ts[i] + ts[i + 1]) / 2;
		Point c = s + (t - s) * x;
		if (is_in_polygon(poly, c) == 2)return false;
	}
	return true;
}



bool exi[40][40];
int n;
void solve() {
	cin >> n;
	vector<int> x(n), y(n);
	vector<Point> poly;
	rep(i, n)cin >> x[i] >> y[i];
	rep(i, n)poly.push_back({ (ld)x[i],(ld)y[i] });
	rep(i, n) {
		rep(j, n) {
			if (i == j)exi[i][j] = true;
			else {
				Point p = { (ld)x[i],(ld)y[i] };
				Point q = { (ld)x[j],(ld)y[j] };
				Line l = { p,q };
				exi[i][j] = edge_in_polygon(poly, l);
			}
		}
	}
	//rep(i, n) {
	//	rep(j, n)cout << exi[i][j];
	//	cout << "\n";
	//}
	vector<ll> ts;
	rep(i, n) {
		ll s = 0;
		rep(j, n)if(exi[i][j]) {
			s |= (1ll << j);
		}
		ts.push_back(s);
	}
	sort(all(ts));
	ts.erase(unique(all(ts)), ts.end());

	vector<ll> vs;
	rep(i, ts.size()) {
		//cout << ts[i] << "\n";
		bool exi = false;
		Rep(j, i + 1, ts.size()) {
			if ((ts[j] & ts[i]) == ts[i])exi = true;
		}
		if (!exi)vs.push_back(ts[i]);
	}
	int len = vs.size();
	int ans = n;
	set<ll> st[11];
	st[0].insert(0);
	rep(i, len) {
		for (int c = 10; c >= 0; c--) {
			for (ll val : st[c]) {
				ll nex = val | vs[i];
				st[c + 1].insert(nex);
			}
		}
	}
	rep(i, 11)if (st[i].count((1ll << n) - 1)) {
		ans=i;break;
	}
	cout << ans << "\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(8);
	init_f();
	//init();
	//int t; cin >> t; rep(i, t)
	//while (cin >> n, n)
		solve();
	return 0;
}
accuracy: 0.08
time_ms: 40
memory_kb: 19896
final_rank: 14

code_snippet: //#pragma GCC optimize("O3")
//#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 20;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll dot(LP a, LP b) {
	return a.first * b.first + a.second * b.second;
}
ll cross(LP a, LP b) {
	return a.first * b.second - a.second * b.first;
}
ll norm2(LP a) {
	return a.first * a.first + a.second * a.second;
}
int ccw(LP a, LP b, LP c) {
	b.first -= a.first; b.second -= a.second;
	c.first -= a.first; c.second -= a.second;
	if (cross(b, c) > 0)return 1;//counter clockwise
	if (cross(b, c) < 0)return -1;//clockwise
	if (dot(b, c) < 0)return 2;//c--a--b on line
	if (norm2(b) < norm2(c))return -2;//a--b--c on line
	return 0;//a--c--b on line
}


bool exi[40][40];
int n;
void solve() {
	cin >> n;
	vector<int> x(n), y(n);
	rep(i, n)cin >> x[i] >> y[i];
	rep(i, n) {
		exi[i][i] = true;
		P nw = { x[i],y[i] };
		P cur = { x[i],y[i] };
		for (int j = 1; j < n; j++) {
			int to = (i + j) % n;
			P nex = { x[to],y[to] };
			if (ccw(nw, cur, nex) == -1) {
				//
			}
			else {
				exi[i][to] = true;
				cur = nex;
			}
		}
	}
	vector<ll> ts;
	rep(i, n) {
		ll s = 0;
		rep(j, n)if(exi[i][j]) {
			s |= (1ll << j);
		}
		ts.push_back(s);
	}
	sort(all(ts));
	ts.erase(unique(all(ts)), ts.end());

	vector<ll> vs;
	rep(i, ts.size()) {
		//cout << ts[i] << "\n";
		bool exi = false;
		Rep(j, i + 1, ts.size()) {
			if ((ts[j] & ts[i]) == ts[i])exi = true;
		}
		if (!exi)vs.push_back(ts[i]);
	}
	int len = vs.size();
	int ans = n;
	rep(i, (1 << len)) {
		int cnt = 0;
		ll z = 0;
		rep(j, len) {
			if (i & (1 << j)) {
				cnt++;
				z |= vs[j];
			}
		}
		if (z == (1ll << n) - 1)ans = min(ans, cnt);
	}
	cout << ans << "\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(8);
	init_f();
	//init();
	//int t; cin >> t; rep(i, t)
	//while (cin >> n, n)
		solve();
	return 0;
}
accuracy: 0.04
time_ms: 10
memory_kb: 19844
final_rank: 19

code_snippet: #include<bits/stdc++.h>
#define MAX 41
#define inf 1<<29
#define linf (1e16)
#define eps (1e-5)
#define Eps (1e-12)
#define mod 1000000007
#define pi acos(-1.0)
#define phi (1.0+sqrt(5.0))/2.0
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define all(a) (a).begin(),(a).end()
#define pd(a) printf("%.10f\n",(double)(a))
#define pld(a) printf("%.10Lf\n",(ld)(a))
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define RFOR(i,a,b) for(int i=(a)-1;(b)<=i;i--)
#define Unique(v) v.erase(unique(all(v)),v.end())
#define equals(a,b) (fabs((a)-(b))<eps)
using namespace std;
typedef long double ld;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<int,double> pid;
typedef pair<double,int> pdi;
typedef pair<double,double> pdd;
typedef vector<int> vi;
typedef vector<pii> vpi;

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

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

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

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

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

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

bool isParallel(Vector a,Vector b){
  return equals(cross(a,b),0.0);
}

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

bool intersect(Line l,Segment s){
  if(ccw(l.p1,l.p2,s.p1)*ccw(l.p1,l.p2,s.p2)==1)return false;
  return true;
}

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

int contains(Polygon g,Point p){
  int n=g.size();
  bool x=false;
  for(int i=0;i<n;i++){
    Vector a=g[i]-p,b=g[(i+1)%n]-p;
    if(abs(cross(a,b))<eps && dot(a,b)<eps)return 1;
    if(a.y>b.y)swap(a,b);
    if(a.y<eps && eps<b.y && cross(a,b)>eps)x=!x;
  }
  if(x)return 2;
  return 0;
}

ull n;
Polygon P;
ull V[MAX] = {};

bool check(Point p1,Point p2){
  if(p1==p2)return true;
  Segment s1 = Segment(p1,p2);
  vector<pair<double,Point> > vp;
  vp.pb(mp(0.0,p1));
  vp.pb(mp(abs(p2-p1),p2));
  FOR(i,0,n){
    Segment s2(P[i],P[(i+1)%n]);
    if(isParallel(s1,s2))continue;
    if(!intersect(s1,s2))continue;
    Point C = getCrossPointLL(s1,s2);
    if(ccw(p1,p2,C)==0)vp.pb(mp(abs(C-p1),C));  
  }
  sort(all(vp));
  vp.erase(unique(all(vp)),vp.end());

  FOR(i,0,vp.size()-1){
    Point a=vp[i].s,b=vp[i+1].s;
    if(a==b)continue;
    Point m=a+(b-a)/2.0;
    if(contains(P,m)==0)return false;
  }
  return true;
}

int lim=0;

bool rec(ull S,ull T,int i,int d){
  if(n<i)return false;
  if(T == (1ll<<(n))-1 )return true;
  if(lim<=d)return false;
  else {
    if(rec(S,T,i+1,d))return true;
    ull NT = T|V[i],NS = S|(1ll<<i); 
    if(rec(NS,NT,i+1,d+1))return true;
  }
  return false;
}

int solve(){
  FOR(i,0,n)
    FOR(j,0,n)
      if(check(P[i],P[j]))V[i] |= (1ll<<j);
  FOR(i,1,n/3+1){
    lim = i;
    if(rec(0ll,0ll,0,0))return i;
  }
  return inf;
}

int main()
{
  cin>>n;
  P.resize(n);
  FOR(i,0,n)cin>>P[i].x>>P[i].y;
  cout<<solve()<<endl;
  return 0;
}
accuracy: 1
time_ms: 930
memory_kb: 3240
final_rank: 4

code_snippet: #include<bits/stdc++.h>
#define MAX 41
#define inf 1<<29
#define linf (1e16)
#define eps (1e-8)
#define Eps (1e-12)
#define mod 1000000007
#define pi acos(-1.0)
#define phi (1.0+sqrt(5.0))/2.0
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define all(a) (a).begin(),(a).end()
#define pd(a) printf("%.10f\n",(double)(a))
#define pld(a) printf("%.10Lf\n",(ld)(a))
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define RFOR(i,a,b) for(int i=(a)-1;(b)<=i;i--)
#define Unique(v) v.erase(unique(all(v)),v.end())
#define equals(a,b) (fabs((a)-(b))<eps)
using namespace std;
typedef long double ld;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<int,double> pid;
typedef pair<double,int> pdi;
typedef pair<double,double> pdd;
typedef vector<int> vi;
typedef vector<pii> vpi;

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

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

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

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

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

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

bool isParallel(Vector a,Vector b){
  return equals(cross(a,b),0.0);
}

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

bool intersect(Line l,Segment s){
  if(ccw(l.p1,l.p2,s.p1)*ccw(l.p1,l.p2,s.p2)==1)return false;
  return true;
}

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

int contains(Polygon g,Point p){
  int n=g.size();
  bool x=false;
  for(int i=0;i<n;i++){
    Vector a=g[i]-p,b=g[(i+1)%n]-p;
    if(abs(cross(a,b))<eps && dot(a,b)<eps)return 1;
    if(a.y>b.y)swap(a,b);
    if(a.y<eps && eps<b.y && cross(a,b)>eps)x=!x;
  }
  if(x)return 2;
  return 0;
}

ull n;
Polygon P;
ull V[MAX] = {};

bool check(Point p1,Point p2){
  if(p1==p2)return true;
  Segment s1 = Segment(p1,p2);
  vector<pair<double,Point> > vp;
  vp.pb(mp(0.0,p1));
  vp.pb(mp(abs(p2-p1),p2));
  FOR(i,0,n){
    Segment s2(P[i],P[(i+1)%n]);
    if(isParallel(s1,s2))continue;
    if(!intersect(s1,s2))continue;
    Point C = getCrossPointLL(s1,s2);
    if(ccw(p1,p2,C)==0)vp.pb(mp(abs(C-p1),C));  
  }
  sort(all(vp));
  vp.erase(unique(all(vp)),vp.end());

  FOR(i,0,vp.size()-1){
    Point a=vp[i].s,b=vp[i+1].s;
    if(a==b)continue;
    Point m=a+(b-a)/2.0;
    if(contains(P,m)==0)return false;
  }
  return true;
}

int lim=0;

bool rec(ull S,ull T,int i,int d){
  if(n<=i)return false;
  if(T == (1ll<<(n))-1 )return true;
  if(lim<=d)return false;
  else {
    if(rec(S,T,i+1,d))return true;
    ull NT = T|V[i],NS = S|(1ll<<i); 
    if(rec(NS,NT,i+1,d+1))return true;
  }
  return false;
}

int solve(){
  FOR(i,0,n)
    FOR(j,0,n)
      if(check(P[i],P[j]))V[i] |= (1ll<<j);
  FOR(i,1,n/3+1){
    lim = i;
    if(rec(0ll,0ll,0,0))return i;
  }
  return inf;
}

int main()
{
  cin>>n;
  P.resize(n);
  FOR(i,0,n)cin>>P[i].x>>P[i].y;
  cout<<solve()<<endl;
  return 0;
}
accuracy: 0.12
time_ms: 530
memory_kb: 3220
final_rank: 7

code_snippet: #include<bits/stdc++.h>
#define MAX 41
#define inf 1<<29
#define linf (1e16)
#define eps (1e-5)
#define Eps (1e-12)
#define mod 1000000007
#define pi acos(-1.0)
#define phi (1.0+sqrt(5.0))/2.0
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define all(a) (a).begin(),(a).end()
#define pd(a) printf("%.10f\n",(double)(a))
#define pld(a) printf("%.10Lf\n",(ld)(a))
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define RFOR(i,a,b) for(int i=(a)-1;(b)<=i;i--)
#define Unique(v) v.erase(unique(all(v)),v.end())
#define equals(a,b) (fabs((a)-(b))<eps)
using namespace std;
typedef long double ld;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<int,double> pid;
typedef pair<double,int> pdi;
typedef pair<double,double> pdd;
typedef vector<int> vi;
typedef vector<pii> vpi;

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

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

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

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

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

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

bool isParallel(Vector a,Vector b){
  return equals(cross(a,b),0.0);
}

bool isParallel(Segment s,Segment t){
  return equals(cross(s.p1-s.p2,t.p1-t.p2),0.0);
}
/*
bool intersect(Line L,Segment s){
  return cross(L.p2-L.p1,s.p1-L.p1)*cross(L.p2-L.p1,s.p2-L.p1)<eps;
}*/

bool intersect(Line l,Segment s){
  if(ccw(l.p1,l.p2,s.p1)*ccw(l.p1,l.p2,s.p2)==-1)return true;
  return false;
}

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

int contains(Polygon g,Point p){
  int n=g.size();
  bool x=false;
  for(int i=0;i<n;i++){
    Vector a=g[i]-p,b=g[(i+1)%n]-p;
    if(abs(cross(a,b))<eps && dot(a,b)<eps)return 1;
    if(a.y>b.y)swap(a,b);
    if(a.y<eps && eps<b.y && cross(a,b)>eps)x=!x;
  }
  if(x)return 2;
  return 0;
}

int n;
Polygon P;
vector<int> V[MAX];

bool check(Point p1,Point p2){
  if(p1==p2)return true;
  Segment s1 = Segment(p1,p2);
  vector<pair<double,Point> > vp;
  vp.pb(mp(0.0,p1));
  vp.pb(mp(abs(p2-p1),p2));
  FOR(i,0,n){
    Segment s2(P[i],P[(i+1)%n]);
    if(isParallel(s1,s2))continue;
    Point C = getCrossPointLL(s1,s2);
    if(ccw(p1,p2,C)==0)vp.pb(mp(abs(C-p1),C));  
  }
  sort(all(vp));
  vp.erase(unique(all(vp)),vp.end());

  FOR(i,0,vp.size()-1){
    Point a=vp[i].s,b=vp[i+1].s;
    if(a==b)continue;
    Point m=a+(b-a)/2.0;
    if(contains(P,m)==0)return false;
  }
  return true;
}

int lim=0,counter=0;
bool S[MAX],T[MAX];

bool rec(int d){
  if(counter==n)return true;
  if(lim<=d)return false;
  FOR(i,0,n){
    if(S[i])continue;
    S[i]=true;
    int c = 0;
    vector<int> tmp;
    FOR(j,0,V[i].size()){
      if(T[V[i][j]])continue;
      T[V[i][j]]=true;
      c+=1;
      tmp.pb(V[i][j]);
    }
    if(c==0)continue;
    counter+=c;
    if(rec(d+1))return true;
    S[i]=false;
    FOR(j,0,tmp.size())T[tmp[j]]=false;
    counter-=c;
  }
  return false;
}

int solve(){
  FOR(i,0,n)
    FOR(j,0,n)
      if(check(P[i],P[j]))V[i].pb(j);
  FOR(i,1,n/3+1){
    lim = i;
    counter = 0;
    fill(S,S+MAX,false);
    fill(T,T+MAX,false);
    if(rec(0))return i;
  }
  return inf;
}

int main()
{
  cin>>n;
  P.resize(n);
  FOR(i,0,n)cin>>P[i].x>>P[i].y;
  cout<<solve()<<endl;
  return 0;
}
accuracy: 0.1
time_ms: 170
memory_kb: 3304
final_rank: 8

code_snippet: #include<bits/stdc++.h>
#define MAX 41
#define inf 1<<29
#define linf (1e16)
#define eps (1e-5)
#define Eps (1e-12)
#define mod 1000000007
#define pi acos(-1.0)
#define phi (1.0+sqrt(5.0))/2.0
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define all(a) (a).begin(),(a).end()
#define pd(a) printf("%.10f\n",(double)(a))
#define pld(a) printf("%.10Lf\n",(ld)(a))
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define RFOR(i,a,b) for(int i=(a)-1;(b)<=i;i--)
#define Unique(v) v.erase(unique(all(v)),v.end())
#define equals(a,b) (fabs((a)-(b))<eps)
using namespace std;
typedef long double ld;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<int,double> pid;
typedef pair<double,int> pdi;
typedef pair<double,double> pdd;
typedef vector<int> vi;
typedef vector<pii> vpi;

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

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

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

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

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

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

bool intersect(Line l,Segment s){
  if(ccw(l.p1,l.p2,s.p1)*ccw(l.p1,l.p2,s.p2)==-1)return true;
  return false;
}

int contains(Polygon g,Point p){
  int n=g.size();
  bool x=false;
  for(int i=0;i<n;i++){
    Vector a=g[i]-p,b=g[(i+1)%n]-p;
    if(abs(cross(a,b))<eps && dot(a,b)<eps)return 1;
    if(a.y>b.y)swap(a,b);
    if(a.y<eps && eps<b.y && cross(a,b)>eps)x=!x;
  }
  if(x)return 2;
  return 0;
}

int n;
Polygon P;
vector<int> V[MAX];

bool check(int a,int b){
  if( (a-1+n)%n==b || a==b || (a+1)%n==b )return true;
  Segment s1 = Segment(P[a],P[b]);
  FOR(i,0,n){
    Segment s2 = Segment(P[i],P[(i+1)%n]);
    if(intersect(s1,s2) && intersect(s2,s1))return false;
  }
  if(contains(P,P[b]+(P[a]-P[b])/2.0)==2)return true;
  return false;
}

int lim=0,counter=0;
bool S[MAX],T[MAX];

bool rec(int d){
  if(counter==n)return true;
  if(lim<=d)return false;
  FOR(i,0,n){
    if(S[i])continue;
    S[i]=true;
    int c = 0;
    vector<int> tmp;
    FOR(j,0,V[i].size()){
      if(T[V[i][j]])continue;
      T[V[i][j]]=true;
      c+=1;
      tmp.pb(V[i][j]);
    }
    if(c==0)continue;
    counter+=c;
    if(rec(d+1))return true;
    S[i]=false;
    FOR(j,0,tmp.size())T[tmp[j]]=false;
    counter-=c;
  }
  return false;
}

int solve(){
  FOR(i,0,n)
    FOR(j,0,n)
      if(check(i,j))V[i].pb(j);
  FOR(i,1,n/3+1){
    lim = i;
    counter = 0;
    fill(S,S+MAX,false);
    fill(T,T+MAX,false);
    if(rec(0))return i;
  }
  return inf;
}

int main()
{
  cin>>n;
  P.resize(n);
  FOR(i,0,n)cin>>P[i].x>>P[i].y;
  cout<<solve()<<endl;
  return 0;
}
accuracy: 0.08
time_ms: 190
memory_kb: 3268
final_rank: 13

code_snippet: #include<bits/stdc++.h>
#define MAX 41
#define inf 1<<29
#define linf (1e16)
#define eps (1e-8)
#define Eps (1e-12)
#define mod 1000000007
#define pi acos(-1.0)
#define phi (1.0+sqrt(5.0))/2.0
#define f first
#define s second
#define mp make_pair
#define pb push_back
#define all(a) (a).begin(),(a).end()
#define pd(a) printf("%.10f\n",(double)(a))
#define pld(a) printf("%.10Lf\n",(ld)(a))
#define FOR(i,a,b) for(int i=(a);i<(b);i++)
#define RFOR(i,a,b) for(int i=(a)-1;(b)<=i;i--)
#define Unique(v) v.erase(unique(all(v)),v.end())
#define equals(a,b) (fabs((a)-(b))<eps)
using namespace std;
typedef long double ld;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<int,double> pid;
typedef pair<double,int> pdi;
typedef pair<double,double> pdd;
typedef vector<int> vi;
typedef vector<pii> vpi;

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

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

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

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

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

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

bool intersect(Line l,Segment s){
  if(ccw(l.p1,l.p2,s.p1)*ccw(l.p1,l.p2,s.p2)==-1)return true;
  return false;
}

int contains(Polygon g,Point p){
  int n=g.size();
  bool x=false;
  for(int i=0;i<n;i++){
    Vector a=g[i]-p,b=g[(i+1)%n]-p;
    if(abs(cross(a,b))<eps && dot(a,b)<eps)return 1;
    if(a.y>b.y)swap(a,b);
    if(a.y<eps && eps<b.y && cross(a,b)>eps)x=!x;
  }
  if(x)return 2;
  return 0;
}

int n;
Polygon P;
bool C[MAX][MAX];

bool check(int a,int b){
  if( (a-1+n)%n==b || a==b || (a+1)%n==b )return true;
  Segment s1 = Segment(P[a],P[b]);
  FOR(i,0,n){
    Segment s2 = Segment(P[i],P[(i+1)%n]);
    if(intersect(s1,s2) && intersect(s2,s1))return false;
  }
  if(contains(P,P[b]+(P[a]-P[b])/2.0)==2)return true;
  return false;
}

bool rec(set<int> S,set<int> T,int d,int lim){
  if(T.size()==n)return true;
  if(lim<=d)return false;
  FOR(i,0,n){
    if(S.count(i)==1)continue;
    set<int> NS = S,NT = T;
    NS.insert(i);
    FOR(j,0,n)
      if(C[i][j])NT.insert(j);
    if(rec(NS,NT,d+1,lim))return true;
  }
  return false;
}

int solve(){
  FOR(i,0,n)
    FOR(j,0,n)
      C[i][j] = check(i,j);
  FOR(i,1,5){
    set<int> S,T;
    if(rec(S,T,0,i))return i;
  }
}

int main()
{
  cin>>n;
  P.resize(n);
  FOR(i,0,n)cin>>P[i].x>>P[i].y;
  cout<<solve()<<endl;
  return 0;
}
accuracy: 0.04
time_ms: 2010
memory_kb: 3236
final_rank: 20

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 45
#define NUM 0.0001

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{
		return x != p.x? x < p.x: y < p.y;
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}

	double x,y;
};

typedef Point Vector;
typedef vector<Point> Polygon;

struct Line{
	Point p[2];
	Line(Point p1,Point p2){
		p[0] = p1;
		p[1] = p2;
	}
	Line(){

	}
};

int N;
ll POW[SIZE];
ll can_watch[SIZE];
Polygon polygon;


int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}

//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(x1 != x2){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_Cross_Point(Line A,Line B){

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}

int ans;

void recursive(ll used,int index,int guards_num,ll tmp_can_watch){

	if(guards_num >= ans || index == N)return;

	//頂点indexに監視人を置かない
	recursive(used,index+1,guards_num,tmp_can_watch);

	//頂点indexに監視人を置く
	ll next_used = used+POW[index];
	ll next_tmp_can_watch = tmp_can_watch|can_watch[index];

	if(next_tmp_can_watch == POW[N]-1){

		ans = min(ans,guards_num+1);
		return;
	}

	recursive(next_used,index+1,guards_num+1,next_tmp_can_watch);
}

int main(){

	POW[0] = 1;
	for(int i = 1; i < SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	scanf("%d",&N);

	double X,Y;

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&X,&Y);
		polygon.push_back(Point(X,Y));
	}

	bool FLG;

	for(int i = 0; i < N; i++){

		can_watch[i] = 0;
	}

	//頂点fromから頂点toを監視できるかをチェック
	for(int from = 0; from < N; from++){
		for(int to = 0; to < N; to++){

			if(to == from){
				can_watch[from] += POW[to];
				continue;
			}

			Line tmp_line = Line(polygon[from],polygon[to]); //頂点from→toの線分

			FLG = true;

			for(int i = 0; i < N; i++){

				Line adj_line = Line(polygon[i],polygon[(i+1)%N]);

				if(!is_Cross(tmp_line,adj_line))continue;

				Vector vec = (polygon[to]-polygon[from])/(abs(polygon[to]-polygon[from]));
				vec = vec*NUM;

				if(contains(polygon,polygon[from]+vec) == 0 || contains(polygon,polygon[to]-vec) == 0){ //線分の端点から少し進んだ点が内部か

					FLG = false;
					break;
				}

				Point cross_point = calc_Cross_Point(tmp_line,adj_line);

				if(abs(tmp_line.p[0]-cross_point) > EPS && abs(tmp_line.p[1]-cross_point) > EPS){ //端点以外での交点

					if(contains(polygon,cross_point+vec) == 0 || contains(polygon,cross_point-vec) == 0){ //交点から少し進んだ点が内部か

						FLG = false;
						break;
					}
				}
			}
			if(!FLG)continue;

			can_watch[from] += POW[to];
		}
	}

	ans = 9;

	recursive(0,0,0,0);

	printf("%d\n",ans);

	return 0;
}
accuracy: 1
time_ms: 670
memory_kb: 3292
final_rank: 2

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

using ld = double;
using ll = long long;
using point = std::complex<ld>;
using polygon = std::vector<point>;

constexpr ld eps = 1e-10;
const ld pi = acos(-1.0);

ld dot(point const& a, point const& b) {
    return std::real(std::conj(a) * b);
}
ld cross(point const& a, point const& b) {
    return std::imag(std::conj(a) * b);
}

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

struct segment {
    segment() : a(0, 0), b(0, 0) {}
    segment(point a, point b) : a(a), b(b) {}
    point a, b;
};

struct line {
    line() : a(0, 0), b(0, 0) {}
    line(point a, point b) : a(a), b(b) {}
    line(segment s) : a(s.a), b(s.b) {}
    point a, b;
};

bool isis_ss(segment s, segment 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;
}

bool isis_sp(segment s, point p) {
    return (std::abs(s.a - p) + std::abs(s.b - p) - std::abs(s.b - s.a) < eps);
}

point is_ll(line s, line t) {
    point sv = s.b - s.a, tv = t.b - t.a;
    assert(cross(sv, tv) != 0);
    return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

vector<point> is_ss(segment s1, segment s2) {
    assert(isis_ss(s1, s2));
    vector<point> res;
    if(cross(s1.b - s1.a, s2.b - s2.a) == 0) {
        if(isis_sp(s1, s2.a)) res.push_back(s2.a);
        if(isis_sp(s1, s2.b)) res.push_back(s2.b);
        if(isis_sp(s2, s1.a)) res.push_back(s1.a);
        if(isis_sp(s2, s1.b)) res.push_back(s1.b);
    } else {
        res.push_back(is_ll(line(s1), line(s2)));
    }
    return res;
}

// 0 -> on, 1 -> in, 2 -> out
int is_in_polygon(polygon const& poly, point p) {
    const int n = poly.size();
    ld sum = 0;
    for(int i = 0; i < n; ++i) {
        point p1 = poly[i], p2 = poly[(i + 1) % n];
        if(isis_sp(segment(p1, p2), p)) {
            return 0;
        }
        sum += arg((p2 - p) / (p1 - p));
    }
    return std::abs(sum) < pi / 2 ? 2 : 1; // @todo: should check < 0.5 ?
}

int dfs(polygon const& ps, int i, ll cur_vis, ll used, vector<ll> const& vis) {
    const int n = ps.size();
    if(cur_vis == (1LL << n) - 1) return __builtin_popcountll(used);
    if(i == n) return 9;
    int res = dfs(ps, i + 1, cur_vis, used, vis);
    if(__builtin_popcountll(used) < 8) {
        res = min(res, dfs(ps, i + 1, cur_vis | vis[i], used | (1LL << i), vis));
    }
    return res;
}

int main() {
    int n; cin >> n;
    polygon ps(n);
    for(int i = 0; i < n; ++i) {
        int x, y; cin >> x >> y;
        ps[i] = point(x, y);
    }

    vector<ll> vis(n);
    for(int i = 0; i < n; ++i) {
        vis[i] = 1LL << i;
        for(int j = 0; j < n; ++j) {
            if(i == j) continue;
            segment s(ps[i], ps[j]);
            bool check = true;
            for(int k = 0; k < n; ++k) {
                segment t(ps[k], ps[(k + 1) % n]);
                if(!isis_ss(s, t)) continue;
                const auto delta = (ps[j] - ps[i]) / abs(ps[i] - ps[j]) * 0.001;
                for(auto p : is_ss(s, t)) {
                    if(abs(s.a - p) > eps && abs(s.b - p) > eps) {
                        check &= is_in_polygon(ps, p + delta) != 2 && is_in_polygon(ps, p - delta) != 2;
                    }
                }
                check &= is_in_polygon(ps, ps[i] + delta) != 2;
                check &= is_in_polygon(ps, ps[j] - delta) != 2;
            }
            if(check) {
                vis[i] |= 1LL << j;
            }
        }
    }

    cout << dfs(ps, 0, 0, 0, vis) << endl;
}
accuracy: 1
time_ms: 1850
memory_kb: 3400
final_rank: 5