P4636 [SHOI2011] 直线拟合
题意
\(n\) 个点,求一条直线,使得祂和离祂最远的点的距离最小,求这个最小值。
\(n\le10^5\)。
思路
把凸包建出来,对于每条凸包上的边,找到以这条边为底,与其祂点构成的三角形中高的最大值。答案就是所有最大高中最小值除以 \(2\)。这个是好求的,直接用旋转卡壳。
代码
要注意判断凸包中所有点共线的情况,否则会死循环。
// Problem: P4636 [SHOI2011] 直线拟合
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4636
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(double&x){scanf("%lf",&x);}
inline void write(double x){printf("%lf",x);}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
const int maxn=100010;
const double eps=1e-5;
int n;
struct point{
double x,y;
bool operator<(const point t)const{
if(abs(x-t.x)<eps) return y<t.y;
return x<t.x;
}
}a[maxn];
vector<int>hull;
bool check(point a,point b,point c){return (b.y-a.y)*(c.x-a.x)+eps>(c.y-a.y)*(b.x-a.x);}
bool check(int a,int b,int c){return check(::a[a],::a[b],::a[c]);}
void find_hull(){
hull.push_back(1);
for(int i=2;i<=n;i++){
while(hull.size()>=2&&check(hull[hull.size()-2],hull.back(),i)) hull.pop_back();
hull.push_back(i);
}
int nwsz=hull.size();
for(int i=n-1;i>=1;i--){
while(hull.size()>nwsz&&!check(i,hull.back(),hull[hull.size()-2])) hull.pop_back();
hull.push_back(i);
}
hull.pop_back();
}
double get_dis(point a,point b){return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));}
double get_dis(point a,point b,point c){
double fm=(b.y-a.y)*c.x-(b.x-a.x)*c.y+b.x*a.y-b.y*a.x;
fm=abs(fm);
return fm/get_dis(a,b);
}
double get_dis(int a,int b,int c){return get_dis(::a[a],::a[b],::a[c]);}
signed main(){
read(n);
for(int i=1;i<=n;i++) read(a[i].x,a[i].y);
sort(a+1,a+1+n);
find_hull();
if(hull.size()==2){write("0.00");return 0;}
bool gx=1;
for(int i=2;i<hull.size();i++) if(get_dis(hull[0],hull[1],hull[i])>eps) gx=0;
if(gx){write("0.00");return 0;}
double ans=INFINITY;
int w=0;
auto get_nxt=[](int x){return (x+1)%hull.size();};
for(int i=0;i<hull.size();i++){
while(get_dis(hull[i],hull[get_nxt(i)],hull[w])<get_dis(hull[i],hull[get_nxt(i)],hull[get_nxt(w)])+eps) w=get_nxt(w);
ans=min(ans,get_dis(hull[i],hull[get_nxt(i)],hull[w]));
}
printf("%.2lf",ans/2);
return 0;
}

浙公网安备 33010602011771号