#include <iostream>
#include <algorithm>
#include <numeric>
#include <cstdint>
#include <cstring>
using namespace std;

using ind_t = uint_least8_t;
using pos_t = int32_t;
using tangent_t = float;

constexpr size_t kSizeArr = 256;
constexpr size_t kShift = 16;
constexpr pos_t kMask = (1 << kShift) - 1;
constexpr ind_t kPruneStep = 8;

pos_t points[kSizeArr];
tangent_t tangents[kSizeArr];
ind_t tmp[kSizeArr];
ind_t sorted[kSizeArr][kSizeArr];
ind_t lefts[kSizeArr][kSizeArr];
ind_t memorize[kSizeArr][kSizeArr];
size_t n;

void readInput()
{
    cin >> n;

    for (size_t i = 0; i < n; ++i)
    {
        pos_t x, y;
        cin >> x >> y;
        points[i] = (x << kShift) + kMask - y;
    }
}

void order()
{
    sort(points, points + n);

    for (size_t i = 0; i < n; ++i)
        points[i] = (points[i] & ~kMask) + kMask - (points[i] & kMask);
}

void preprocess()
{
    for (size_t i_center = 0; i_center < n; ++i_center)
    {
        ind_t ind = 0;
        const pos_t x_center = points[i_center] >> kShift;
        const pos_t y_center = points[i_center] & kMask;
        const auto nm1 = n - 1;
        iota(tmp, tmp + n, 0);

        for (size_t i_pt = 0; i_pt < n; ++i_pt)
        {
            const pos_t x = points[i_pt] >> kShift;
            const pos_t y = points[i_pt] & kMask;

            tangents[i_pt] =
                static_cast<tangent_t>(y - y_center) /
                static_cast<tangent_t>(x - x_center);
        }

        tmp[i_center] = tmp[nm1];
        tangents[i_center] = tangents[nm1];

        sort(tmp, tmp + nm1, [&](ind_t l, ind_t r)
        {
            return tangents[l] < tangents[r];
        });

        const auto mkLeft = [&](size_t ii)
        {
            lefts[tmp[ii]][i_center] = ind;
        };

        const auto mkSorted = [&](size_t ii)
        {
            sorted[i_center][ind++] = tmp[ii];
        };

        for (size_t i = 0; i < nm1; ++i)
        {
            if ((points[tmp[i]] >> kShift) < x_center)
                mkLeft(i);
            else
                mkSorted(i);
        }

        for (size_t i = 0; i < nm1; ++i)
        {
            if ((points[tmp[i]] >> kShift) >= x_center)
                mkLeft(i);
            else
                mkSorted(i);
        }

        if ((points[tmp[nm1 - 1]] >> kShift) == x_center &&
            (points[tmp[nm1 - 1]] & kMask) > y_center
        )
            lefts[tmp[nm1 - 1]][i_center] = 0;

        sorted[i_center][ind] = static_cast<ind_t>(i_center);
    }
}

void prune(size_t from, size_t to)
{
    for (size_t i = to; i < n; ++i)
    {
        size_t new_j = 0;
        ind_t delta = 0;
        for (size_t j = 0; j < n - from; ++j)
        {
            tmp[j] = delta;

            if (sorted[i][j] < to)
                ++delta;
            else
                sorted[i][new_j++] = sorted[i][j];
        }

        for (size_t j = to; j < n; ++j)
            lefts[j][i] = static_cast<ind_t>(lefts[j][i] - tmp[lefts[j][i]]);
    }
}

unsigned dpStep(ind_t i_left, ind_t from, ind_t to_ind)
{
    ind_t child = sorted[from][to_ind];

    while (child < i_left)
        child = sorted[from][++to_ind];

    if (child == i_left)
        return 1;

    if (auto v = memorize[from][child])
        return v;

    const auto x = max(dpStep(i_left, child, lefts[from][child]) + 1,
                       dpStep(i_left, from, static_cast<ind_t>(to_ind + 1)));

    memorize[from][child] = static_cast<ind_t>(x);
    return x;
}

unsigned dp(ind_t i_left)
{
    return dpStep(i_left, i_left, 0);
}

unsigned solve()
{
    unsigned best = 0;

    ind_t i_prune = kPruneStep;
    for (ind_t i_left = 0; i_left < n - best; ++i_left)
    {
        memset((void*)memorize, 0, sizeof(memorize));
        best = max(best, dp(i_left));

        if (--i_prune == 0)
        {
            i_prune = kPruneStep;
            prune(i_left + 1 - kPruneStep, i_left + 1);
        }
    }

    return best;
}

int main()
{
    readInput();
    order();
    preprocess();
    cout << solve() << '\n';
}
