#include<algorithm>
#include<algorithm>     //sort,二分探索,など
#include<bitset>        //固定長bit集合
#include<cmath>         //pow,logなど
#include<complex>       //複素数
#include<deque>         //両端アクセスのキュー
#include<functional>    //sortのgreater
#include<iomanip>       //setprecision(浮動小数点の出力の誤差)
#include<iostream>      //入出力
#include<iterator>      //集合演算(積集合,和集合,差集合など)
#include<map>           //map(辞書)
#include<numeric>       //iota(整数列の生成),gcdとlcm(c++17)
#include<queue>         //キュー
#include<set>           //集合
#include<stack>         //スタック
#include<string>        //文字列
#include<unordered_map> //イテレータあるけど順序保持しないmap
#include<unordered_set> //イテレータあるけど順序保持しないset
#include<utility>       //pair
#include<vector>        //可変長配列

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<ld> vld;
typedef vector<string> vs;
typedef vector<bool> vb;
typedef vector<vector<int>> vvi;
typedef vector<vector<ll>> vvll;
typedef vector<vector<ld>> vvld;
typedef vector<vector<string>> vvs;
typedef vector<vector<bool>> vvb;
typedef pair<int, int> P;
const ll MOD = 1000000007;
const ll INF = 1000000000000000000;
#define rep(i,n) for(int i=0;i<n;i++)
#define repl(i,s,e) for(int i=s;i<e;i++)
#define reple(i,s,e) for(int i=s;i<=e;i++)
#define revrep(i,n) for(int i=n-1;i>=0;i--)
#define all(x) (x).begin(),(x).end()

template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }


class UnionFind
{
	//par[i]：ノードiの親
	//count[i]：iが親の時、iが属するグループのノード数
	vector<int> par;
	vector<int> count;

	int m_groupCount = 0;

public:
	UnionFind(int N)
	{
		//1始まりのときに必要
		//par.push_back(0);
		//count.push_back(0);

		m_groupCount = N;

		rep(i, N)
		{
			//最初は全てが根であるとして初期化
			par.push_back(i);
			count.push_back(1);
		}
	}

	//データxが属する木の根を再帰で得る：root(x) = {xの木の根}
	int root(int x)
	{
		if (par[x] == x) return x;

		//ついでに親を張り替え
		return par[x] = root(par[x]);
	}

	//xとyの木を併合
	void unite(int x, int y)
	{
		int rx = root(x);
		int ry = root(y);
		if (rx == ry) return;
		//xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
		par[rx] = ry;

		//要素数の変更
		count[ry] += count[rx];
		count[rx] = 0;

		//木の併合によってグループが1つ減る
		m_groupCount--;
	}

	// 2つのデータx, yが属する木が同じならtrueを返す
	bool same(int x, int y)
	{
		return root(x) == root(y);
	}

	//指定したデータxが属するグループの要素数を返す
	int size(int x)
	{
		return count[root(x)];
	}

	//UnionFindのグループの個数を返す
	int groupCount()
	{
		return m_groupCount;
	}

	//UnionFindのコピー処理
	UnionFind copy()
	{
		UnionFind uf(par.size());

		//元のUnionFindの親情報を再現
		rep(i, par.size())
		{
			uf.unite(i, this->root(i));
		}

		return uf;
	}
};


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

    int N;
    cin >> N;

    vi X(N), Y(N);
    rep(i, N) cin >> X[i] >> Y[i];

    set<P> s;
    rep(i, N)
    {
        rep(j, N)
        {
			s.emplace(X[i] - X[j], Y[i] - Y[j]);
        }
    }

    int ans = 10000000;

    for (auto p : s)
    {
		UnionFind uf(N);

        rep(i, N)
        {
            rep(j, N)
            {
				if (X[i] - X[j] == p.first && Y[i] - Y[j] == p.second) uf.unite(i, j);
            }
        }

		chmin(ans, uf.groupCount());
    }

    cout << ans << endl;

    return 0;
}

Measured memory_bytes: 384