Description
给你一个整数坐标的点集,询问点集中最小的三角形周长是多少。退化的三角形也是允许的(面积为0)。
Input
第一行一个整数n表示共有n个点
接下来n行每行两个整数xi,yi表示点的坐标
保证没有重复点
Output
仅一行包含一个实数表示最小的三角形周长,输出和标准答案相差10^-9之内都被认为是正确的。
Sample Input
4
0 0
2 0
0 2
2 2
Sample Output
6.828427124746
Data Constraint
0 < n<=100000
题解
首先先看最最暴力的方法,
O(n3)
O
(
n
3
)
的暴力匹配。
很显然这是不可行的。
而像这种题目一般就是用分治来做,
按照x从小到大排序,
每次选择最中间,建点集分成大小相同的两个部分。
现在就只需要考虑如何求出跨过中间线的三角形。
不过在此之前,就可以通过分治左右两边的点集得到一个最小值,
而通过这个最小值,对不少点进行剪枝。
假设当前的最小值为p,
你们肯能成为新的最小值的三个点只可能分布在一个边长为p,p/2的长方形中,
也就是说中线往左右各p/2里面的所有点。
于是就先将这些点拿出来按照y排序,
然后用过队列维护,
每次加入一个点,然后跟队列里面所有的点暴力配对。
最后再将一些不可能成为更新答案的点踢掉。
code
#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 100003
#define M 103
#define db double
#define P putchar
#define G getchar
#define inf 998244353
#define pi 3.1415926535897932384626433832795
using namespace std;
char ch;
void read(ll &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
ll abs(ll x){return x<0?-x:x;}
ll sqr(ll x){return x*x;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}
struct node
{
ll x,y;
}a[N],b[N];
db dis(node a,node b)
{
return sqrt((db)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
db get(node a,node b,node c)
{
return dis(a,b)+dis(a,c)+dis(b,c);
}
bool cmp(node a,node b)
{
return a.x<b.x;
}
bool cmp1(node a,node b)
{
return a.y<b.y;
}
ll n;
db solve(int l,int r)
{
int m=(l+r)>>1;
db mi=2147483647;
if(r-l<2)return mi;
mi=min(solve(l,m),solve(m+1,r));
db t=mi/2,w=a[m].x;
int st,fi;
for(st=m;st>=l && w-a[st].x<=t;st--);
for(fi=m;fi<=r && a[fi].x-w<=t;fi++);
for(int i=st+1;i<fi;i++)b[i-st]=a[i];
int p=fi-st-1;
sort(b+1,b+1+p,cmp1);
int id=1;
for(int i=1;i<=p;i++)
{
for(int j=id;j<i;j++)
for(int k=j+1;k<i;k++)
mi=min(mi,get(b[i],b[j],b[k]));
for(t=mi/2;b[i].y-b[id].y>t && id<i;id++);
}
return mi;
}
int main()
{
read(n);
for(int i=1;i<=n;i++)
read(a[i].x),read(a[i].y);
sort(a+1,a+1+n,cmp);
printf("%.10lf",solve(1,n));
return 0;
}