#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';
}