#include <iostream>
#include <sstream>
#include <iomanip>
#include <vector>
#include <string>
#include <map>
#include <set>
#include <algorithm>
#include <numeric>
#include <iterator>
#include <complex>
#include <queue>
#include <stack>
#include <cmath>
#include <cassert>
#include <cstring>
using namespace std;
typedef long long LL;

struct edge {
	int y, x1, x2;
	edge(){}
	edge(int y, int x1, int x2) :y(y),x1(min(x1,x2)),x2(max(x1,x2)) {}
	bool operator<( const edge& rhs ) const {
		if( y != rhs.y ) return y<rhs.y;
		if( x1 != rhs.x1 ) return x1<rhs.x1;
		return x2 < rhs.x2;
	}
};

class RestoringPolygon {
public:
	int restore(vector <int> x1, vector <int> x2, vector <int> y) 
	{
		int N = x1.size();

		vector<edge> e;
		for(int i=0; i!=N; ++i)
			e.push_back( edge(y[i], x1[i], x2[i]) );
		sort(e.begin(), e.end());

		int ans = 0;
		for(int m=1; m<(1<<N); ++m)
			ans = max(ans, calc(e,m));
		return ans;
	}

	int calc(vector<edge>& e_, int m)
	{
		vector<edge> e;
		for(int i=0; (1<<i)<=m; ++i)
			if( m & (1<<i) )
				e.push_back( e_[i] );

		if( e.size() <= 1 )
			return 0;

		typedef pair<int,int> point;
		typedef map< point, vector<point> > graph;
		graph G;
		for(int i=0; i<e.size(); ++i)
		{
			int y = e[i].y;
			int xx[] = {e[i].x1, e[i].x2};

			G[ point(e[i].x1,y) ].push_back( point(e[i].x2,y) );
			G[ point(e[i].x2,y) ].push_back( point(e[i].x1,y) );

			for(int k=0; k<2; ++k) {
				int x = xx[k];
				for(int j=i-1; j>=0; --j)
					if( e[j].x1 == x ) {
						point p1(x, y);
						point p2(e[j].x1, e[j].y);
						if( G[p2].size() < 2 ) {
							G[p1].push_back(p2);
							G[p2].push_back(p1);
						}
					} else if( e[j].x2 == x ) {
						point p1(x, y);
						point p2(e[j].x2, e[j].y);
						if( G[p2].size() < 2 ) {
							G[p1].push_back(p2);
							G[p2].push_back(p1);
						}
					} else if( e[j].x1 < x && x < e[j].x2 ) {
						break;
					}
			}
		}

		for(graph::iterator it=G.begin(); it!=G.end(); ++it)
			if( it->second.size() != 2 )
				return 0;

		point s = G.begin()->first;
		point p = s, p2 = G[p][0];
		for(int c=2 ;; ++c) {
			point q = (G[p2][0] == p ? G[p2][1] : G[p2][0]);
			p=p2, p2=q;
			if( q == s )
				return c==e.size()*2 ? c : 0;
		}
	}
};

// BEGIN CUT HERE
#include <ctime>
double start_time;string timer() { ostringstream os; os << " (" << int((clock()-start_time)/CLOCKS_PER_SEC*1000) << " msec)"; return os.str(); }

template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
int verify_case(const int &Expected, const int &Received) { if (Expected == Received) cerr << "PASSED" << timer() << endl; else { cerr << "FAILED" << timer() << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } return 0;}

template<int N> struct Case_ { Case_(){start_time=clock();} };
char Test_(...);
int Test_(Case_<0>) {
	int x1_[] = {1,2,3,1};
	  vector <int> x1(x1_, x1_+sizeof(x1_)/sizeof(*x1_)); 
	int x2_[] = {2,3,5,5};
	  vector <int> x2(x2_, x2_+sizeof(x2_)/sizeof(*x2_)); 
	int y_[] = {1,4,2,0};
	  vector <int> y(y_, y_+sizeof(y_)/sizeof(*y_)); 
	int RetVal = 8; 
	return verify_case(RetVal, RestoringPolygon().restore(x1, x2, y)); }
int Test_(Case_<1>) {
	int x1_[] = {1,1,2,2};
	  vector <int> x1(x1_, x1_+sizeof(x1_)/sizeof(*x1_)); 
	int x2_[] = {3,3,4,4};
	  vector <int> x2(x2_, x2_+sizeof(x2_)/sizeof(*x2_)); 
	int y_[] = {0,2,1,3};
	  vector <int> y(y_, y_+sizeof(y_)/sizeof(*y_)); 
	int RetVal = 4; 
	return verify_case(RetVal, RestoringPolygon().restore(x1, x2, y)); }
int Test_(Case_<2>) {
	int x1_[] = {1};
	  vector <int> x1(x1_, x1_+sizeof(x1_)/sizeof(*x1_)); 
	int x2_[] = {2};
	  vector <int> x2(x2_, x2_+sizeof(x2_)/sizeof(*x2_)); 
	int y_[] = {1};
	  vector <int> y(y_, y_+sizeof(y_)/sizeof(*y_)); 
	int RetVal = 0; 
	return verify_case(RetVal, RestoringPolygon().restore(x1, x2, y)); }
int Test_(Case_<3>) {
	int x1_[] = {0,0,0};
	  vector <int> x1(x1_, x1_+sizeof(x1_)/sizeof(*x1_)); 
	int x2_[] = {1000,1000,1000};
	  vector <int> x2(x2_, x2_+sizeof(x2_)/sizeof(*x2_)); 
	int y_[] = {0,1,2};
	  vector <int> y(y_, y_+sizeof(y_)/sizeof(*y_)); 
	int RetVal = 4; 
	return verify_case(RetVal, RestoringPolygon().restore(x1, x2, y)); }
int Test_(Case_<4>) {
	int x1_[] = {0,1,1,2};
	  vector <int> x1(x1_, x1_+sizeof(x1_)/sizeof(*x1_)); 
	int x2_[] = {1,0,2,1};
	  vector <int> x2(x2_, x2_+sizeof(x2_)/sizeof(*x2_)); 
	int y_[] = {0,4,2,3};
	  vector <int> y(y_, y_+sizeof(y_)/sizeof(*y_)); 
	int RetVal = 8; 
	return verify_case(RetVal, RestoringPolygon().restore(x1, x2, y)); }
int Test_(Case_<5>) {
	int x1_[] = {696, -193, -193, 367};
	  vector <int> x1(x1_, x1_+sizeof(x1_)/sizeof(*x1_)); 
	int x2_[] = {367, -276, -276, 696};
	  vector <int> x2(x2_, x2_+sizeof(x2_)/sizeof(*x2_)); 
	int y_[] = {-14, 168, -14, 168};
	  vector <int> y(y_, y_+sizeof(y_)/sizeof(*y_)); 
	int RetVal = 4; 
	return verify_case(RetVal, RestoringPolygon().restore(x1, x2, y)); }
int Test_(Case_<6>) {
	int x1_[] = { 0,  1, 6, 5, 5,  1,  6,  1,  0,  0,  9};
	  vector <int> x1(x1_, x1_+sizeof(x1_)/sizeof(*x1_)); 
	int x2_[] = { 5,  9, 9, 6, 6,  0,  9,  0,  1,  5,  6};
	  vector <int> x2(x2_, x2_+sizeof(x2_)/sizeof(*x2_)); 
	int y_[] = { 1,  4, 5, 3, 2,  0,  0,  2,  3,  5,  1};
	  vector <int> y(y_, y_+sizeof(y_)/sizeof(*y_)); 
	int RetVal = 16; 
	return verify_case(RetVal, RestoringPolygon().restore(x1, x2, y)); }

template<int N> void Run_() { cerr << "Test Case #" << N << "..." << flush; Test_(Case_<N>()); Run_<sizeof(Test_(Case_<N+1>()))==1 ? -1 : N+1>(); }
template<>      void Run_<-1>() {}
int main() { Run_<0>(); }
// END CUT HERE

