题意:
给
n
个点,求最小三角形。
题解:
好题啊。。
(后面有动态凸包)
有一种简单的做法:
首先如果选定了底边的两点,那么还需要选择一条离这条底边最近的点。
将当前坐标系y轴旋转这条底边,那么选择
|X|
最小的点。
考虑按照斜率从小到大枚举底边。
对于两个点
a,b
来说,若一条底边
c,d
的斜率小于
a,b
斜率,且在
c,d
的坐标系下
ax>bx
,那么在所有斜率小于
a,b
的坐标系下都满足
ax>bx
。所有斜率大于
a,b
的底边都满足
bx>ax
。那么一开始建立一个序列,每次枚举到
a,b
边就交换
a,b
位置就可以保证序列一直有序,查找可以做到
O(1)
。总时间复杂度
O(n2logn)
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
return i*f;
}
const int Maxn=1e3+50;
const double INF=1e18;
int n,tot,pos[Maxn];
double ans=INF;
struct point{
double x,y;
int id;
point(double x=0,double y=0):x(x),y(y){}
friend inline bool operator <(const point &a,const point &b){
return a.x<b.x;
}
friend inline point operator -(const point &a,const point &b){
return point(a.x-b.x,a.y-b.y);
}
friend inline double operator *(const point &a,const point &b){
return a.x*b.y-a.y*b.x;
}
}p[Maxn];
struct line{
int a,b;
double slope;
friend inline bool operator <(const line &a,const line &b){
return a.slope<b.slope;
}
}l[Maxn*Maxn];
inline double calc(const point &a,const point &b,const point &c){
return fabs((a-b)*(a-c));
}
int main(){
n=read();
for(int i=1;i<=n;i++)
p[i].x=read(),p[i].y=read(),p[i].id=i;
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
l[++tot]=(line){i,j,(p[i].x==p[j].x)?INF:(p[i].y-p[j].y)/(p[i].x-p[j].x)};
sort(l+1,l+tot+1);sort(p+1,p+n+1);
for(int i=1;i<=n;i++)pos[p[i].id]=i;
for(int i=1;i<=tot;i++){
int a=l[i].a,b=l[i].b;
swap(pos[a],pos[b]),swap(p[pos[a]],p[pos[b]]);
if(pos[a]>1&&pos[a]-1!=pos[b])ans=min(ans,calc(p[pos[a]],p[pos[b]],p[pos[a]-1]));
if(pos[a]<n&&pos[a]+1!=pos[b])ans=min(ans,calc(p[pos[a]],p[pos[b]],p[pos[a]+1]));
if(pos[b]>1&&pos[b]-1!=pos[a])ans=min(ans,calc(p[pos[a]],p[pos[b]],p[pos[b]-1]));
if(pos[b]<n&&pos[b]+1!=pos[a])ans=min(ans,calc(p[pos[a]],p[pos[b]],p[pos[b]+1]));
}
printf("%.2f\n",ans/2.0);
}
动态凸包:
考虑按照x轴依次加入点,将所有横坐标比他大的点按照到这个点的极角排序,考虑所有包含当前点的三角形必然是由这个点到右边某个点的直线加上一个最近距离点构成的,依次加入点之后在凸包上找就行了。时间复杂度
O(n2logn)
(代码是真的难调,可读性可能比较低。。)
#include<bits/stdc++.h>
using namespace std;
inline int read(){
char ch=getchar();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
return i*f;
}
const int Maxn=1e3+50;
const double INF=1e18;
const double eps=1e-9;
int n,now;
double ans=INF;
struct point{
double x,y;
double slope;
point(double x=0,double y=0,double slope=0):x(x),y(y),slope(slope){}
friend inline point operator -(const point &a,const point &b){return point(a.x-b.x,a.y-b.y);}
friend inline double operator *(const point &a,const point &b){return a.x*b.y-a.y*b.x;}
inline double norm(){return sqrt(x*x+y*y);}
}p[Maxn],tp[Maxn],tp2[Maxn];
#define calc(a,b,c) (fabs((a-b)*(c-b)))
inline bool cmpx(const point &a,const point &b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
inline bool cmpslope(const point &a,const point &b){
if(a.slope!=b.slope)return a.slope<b.slope;
else return a.y<b.y;
}
struct cmp_x{
inline bool operator ()(const point &a,const point &b){return a.x<b.x||(a.x==b.x&&a.y<b.y);}
};
inline int sign(const double x){
return (x>eps)-(x<-eps);
}
struct cmp_slope{
inline bool operator ()(const point &a,const point &b){
return sign(a.slope - b.slope) > 0;
}
};
set<point,cmp_x>S_x;
set<point,cmp_slope>S_t;
typedef set<point>::iterator it;
inline point findsuf(const point &a){
it t=S_t.lower_bound(a);
if(t==S_t.end()||sign(t->slope-a.slope)<0)
--t;
return *t;
}
inline void ins(const point &a){
it suf=S_x.lower_bound(a),pre=suf;
int insbz=0;
if(suf!=S_x.begin()&&suf!=S_x.end()&&((*suf-a)*(*--pre-a)>=0))return;
if(suf!=S_x.begin()){
if(suf==S_x.end())--pre;
while(pre!=S_x.begin()){
it t=pre;--t;
if((*t-a)*(*pre-a)>=0){
S_t.erase(S_t.find(*pre));
S_x.erase(pre);
pre=t;
}
else break;
}
point tmp=a;tmp.slope=atan2(a.y-pre->y,a.x-pre->x);
S_x.insert(tmp);S_t.insert(tmp);
}else insbz=1;
if(suf!=S_x.end()){
while(suf!=--S_x.end()){
it t=suf;++t;
if((*suf-a)*(*t-a)>=0){
S_t.erase(S_t.find(*suf));
S_x.erase(suf);
suf=t;
}
else break;
}
point tmp=*suf;
S_t.erase(S_t.find(*suf));
S_x.erase(suf);
tmp.slope=atan2(tmp.y-a.y,tmp.x-a.x);
S_t.insert(tmp);S_x.insert(tmp);
}
if(insbz){
point tmp=point(a.x,a.y,INF);
S_x.insert(tmp);
S_t.insert(tmp);
}
}
int main(){
n=read();
for(int i=1;i<=n;i++)p[i].x=read(),p[i].y=read();
sort(p+1,p+n+1,cmpx);
for(now=1;now<n-1;now++){
memcpy(tp+now+1,p+now+1,sizeof(point)*(n-now));
for(int i=now+1;i<=n;i++)tp[i].slope=(atan2(tp[i].y-p[now].y,tp[i].x-p[now].x));
sort(tp+now+1,tp+n+1,cmpslope);
S_x.clear();S_t.clear();
point t(tp[now+1].x,tp[now+1].y,INF);
S_x.insert(t);S_t.insert(t);
for(int i=now+2;i<=n;i++){
t=findsuf(point(0,0,atan2(tp[i].y-p[now].y,tp[i].x-p[now].x)));
ans=min(ans,calc(t,tp[i],p[now]));
ins(tp[i]);
}
}
printf("%.2f\n",ans/2.0);
}