POJ - 3525 E - Most Distant Point from the Sea
题意:给你一个日本, 日本中有一个地方, 离海的最近距离比其他地方的最近距离都大.要你求该地到海的最近距离.
也就是给你一个凸包, 在里面放一个最大的圆, 求出圆的半径
解法:
可以二分半径
每次将所有线段向圆心平移mid个单位长度
如果还存在核,则l=mid,否则r=mid
代码:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1e3+5;
const double EPS=1e-9;
const double PI=acos(-1);
inline int sgn(double a){ return a < -EPS ? -1 : a > EPS; }
inline int cmp(double a, double b){ return sgn(a-b); }
int n,m,T;
struct Point;
struct Line;
typedef Point Vector;
struct Point{
double x,y;
Point(){}
Point(double a, double b):x(a),y(b){}
double len(){return sqrt(x*x+y*y);}
Vector Normal(){//单位法向量逆时针旋转90
return Vector(-y/len(),x/len());
}
void read(){scanf("%lf%lf",&x,&y);}
Point operator+(Vector v){return {x+v.x,y+v.y};}
Vector operator-(Point p){return {x-p.x,y-p.y};}
double operator^(Vector v){return x*v.y-y*v.x;}//叉乘
double operator*(Vector v){return x*v.x+y*v.y;}//点乘
Vector operator*(double d){return {x*d,y*d};}
Vector operator/(double d){return {x/d,y/d};}
bool operator==(Point p){return cmp(x,p.x)==0&&cmp(y,p.y)==0;}
bool operator<(Point p){if(cmp(x,p.x)==0) return y<p.y;return x<p.x;}
};
struct Line{
Line(){}
Line(Point a,Point b){s=a;e=b;ang=atan2(e.y-s.y,e.x-s.x);}
Point point(double t){return s + (e - s)*t;}//返回点P = v + (p - v)*t
Point operator &(Line &b){
double t=((s-b.s)^(b.s-b.e))/((s-e)^(b.s-b.e));
return s+(e-s)*t;
}
Point s,e;
double ang;
};
Line Q[1510];
Point p[1510];
Line L[1510];
bool HPIcmp(Line a,Line b) {
if (fabs(a.ang - b.ang) > EPS)return a.ang < b.ang;
else return ((a.s - b.s) ^ (b.e - b.s)) < 0;
}
bool HPI(Line line[],int n,Point res[],int &resn) {
int tot = n;
sort(line, line + n, HPIcmp);
tot = 1;
for (int i = 1; i < n; i++){ // 去掉右边的线段,保留左边的线段。
if (fabs(line[i].ang - line[i - 1].ang) > EPS)
line[tot++] = line[i];
}
int head = 0, tail = 1;
Q[0] = line[0];
Q[1] = line[1];
resn = 0;
for (int i = 2; i < tot; i++) {
if (fabs((Q[tail].e - Q[tail].s) ^ (Q[tail - 1].e - Q[tail - 1].s)) < EPS ||
fabs((Q[head].e - Q[head].s) ^ (Q[head + 1].e - Q[head + 1].s)) < EPS)
return false;
while (head < tail && (((Q[tail] & Q[tail - 1]) - line[i].s) ^ (line[i].e - line[i].s)) > EPS)
tail--;
while (head < tail && (((Q[head] & Q[head + 1]) - line[i].s) ^ (line[i].e - line[i].s)) > EPS)
head++;
Q[++tail] = line[i];
}
while (head < tail && (((Q[tail] & Q[tail - 1]) - Q[head].s) ^ (Q[head].e - Q[head].s)) > EPS)
tail--;
while (head < tail && (((Q[head] & Q[head + 1]) - Q[tail].s) ^ (Q[tail].e - Q[tail].s)) > EPS)
tail--;
return tail > head + 1;
}
double CalcArea(Point p[],int n) {
double ans = 0;
for (int i = 0; i < n; i++) {
ans += (p[i] ^ p[(i + 1) % n]) / 2;
}
return ans;
}
Line tmp[MAXN];
void solve(){
double l=0,r=10000;
while(cmp(l,r)){
double mid=(l+r)/2;
for(int i=0;i<n;i++){
Vector v=L[i].e-L[i].s;
v=v.Normal();//垂直线段指向圆心的单位法向量
tmp[i]={L[i].s+v*mid,L[i].e+v*mid};
}
int resn=0;
if(HPI(tmp,n,p,resn)) l=mid;
else r=mid;
}
printf("%.6f\n",l);
}
void init(){
for(int i=0;i<n;i++)
p[i].read();
if(CalcArea(p,n)<0)
reverse(p,p+n);
for(int i=0;i<n;i++)
L[i]={p[i],p[(i+1)%n]};
}
int main(){
while(~scanf("%d",&n)&&n){
init();
solve();
}
return 0;
}
来源:CSDN
作者:0ng
链接:https://blog.csdn.net/weixin_43804251/article/details/104136861