分析
黄学长说随机能过,事实上似乎数据加强了emmm
如果我们确定了2个点以后,第三个点有必要去盲目的枚举吗?答案是否定的。实际上我们把经过这两点的线看成一个斜率,把他当成y轴你会发现第三个点明显是在坐标系左右找一个离”y轴”最近的点来算面积更新答案。然后我们可以继续思考,发现我们可以把点按照某个斜率当成”y轴”进行“从左到右”的排序,这样当2点共线的时候,用这两个点的左右2个点去更新答案就好了。也就是说我们采用旋转坐标系的方法,一开始按x坐标排好序,认为直接用竖着的那条斜率,然后维护的话每次其实当两点共线后只要交换他们就能得到斜率转过该事件点的序列。所以我们可以预处理出所有可行的斜率,当成事件点,不断转动坐标系更新答案就好。这样复杂度只有n^2,期望得分100
代码
hzw说这个随机能过,假
#include <bits/stdc++.h>
#define inf 1000000000
#define ll long long
int read()
{
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
int n,block,cnt;
double ans = 1e60;
struct P
{
double x,y;
}p[1005];
P operator -(P a,P b)
{
return (P){a.x - b.x, a.y - b.y};
}
double cross(P a,P b)
{
return a.x * b.y - a.y * b.x;
}
bool operator <(P a,P b)
{
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
P rotate(P a,double x)
{
return (P){a.x * cos(x) - a.y * sin(x), a.y * cos(x) + a.x * sin(x)};
}
void cal(int a,int b)
{
for (int i = a; i <= b - 2; i++)
for (int j = i + 1; j <= b - 1; j++)
for (int k = j + 1; k <= b; k++)
ans = std::min(ans, abs(cross(p[i] - p[k], p[j] - p[k])) / 2.0);
}
void solve()
{
double t = rand() / 10000;
for (int i = 1; i <= n; i++)
p[i] = rotate(p[i],t);
std::sort(p + 1, p + n + 1);
for (int i = 1; i <= cnt; i++)
{
int t1 = block * (i - 1) + 1, t2 = block * i;
t2 = std::min(t2,n);
cal(t1,t2);
}
}
int main()
{
n = read();
srand(time(0));
block = sqrt(n) + 10;
cnt = n / block + (n % block != 0);
for (int i = 1; i <= n; i++)
p[i].x = read(), p[i].y = read();
for (int i = 1; i <= 100; i++)
solve();
printf("%.2lf",ans);
}
#include <bits/stdc++.h>
using namespace std;
const int mxn = 1005;
int n, m, p;
double ans = 1e200;
struct Pair
{
double x, y;
inline Pair(void) {};
inline Pair(double a, double b)
: x(a), y(b) {};
}P[mxn];
inline Pair operator - (const Pair &a, const Pair &b)
{
return Pair(a.x - b.x, a.y - b.y);
}
struct Line
{
int a, b;
double k;
inline void set(int i, int j)
{
a = i;
b = j;
k = (P[i].y - P[j].y) / (P[i].x - P[j].x);
}
}L[mxn * mxn];
inline bool cmpP(const Pair &a, const Pair &b)
{
if (a.x != b.x)
return a.x < b.x;
else
return a.y < b.y;
}
inline bool cmpL(const Line &a, const Line &b)
{
return a.k < b.k;
}
inline double cross(const Pair &a, const Pair &b)
{
return a.x * b.y - a.y * b.x;
}
int ps[mxn], rk[mxn];
signed main(void)
{
cin >> n;
for (int i = 0; i < n; ++i)
cin >> P[i].x >> P[i].y;
sort(P, P + n, cmpP);
for (int i = 0; i < n; ++i)
for (int j = 0; j < i; ++j)
L[m++].set(i, j);
sort(L, L + m, cmpL);
for (int i = 0; i < n; ++i)
rk[i] = ps[i] = i;
for (int i = 0; i < m; ++i)
{
int a = L[i].a, b = L[i].b;
if (ps[a] > ps[b])swap(a, b);
if (ps[a] > 1 - 1)ans = min(ans, fabs(cross(P[a] - P[b], P[rk[ps[a] - 1]] - P[b])));
if (ps[b] < n - 1)ans = min(ans, fabs(cross(P[a] - P[b], P[rk[ps[b] + 1]] - P[a])));
swap(ps[a], ps[b]), swap(rk[ps[a]], rk[ps[b]]);
}
cout << fixed << setprecision(2) << ans / 2.0 << endl;
}