LA 3890 離海最遠的點(半平面交)

題目:https://vjudge.net/problem/UVALive-3890

二分法,通過收縮凸邊型,直到半平面交爲空集。

#include<bits/stdc++.h>
using namespace std;

#include<bits/stdc++.h>
using namespace std;

struct Point{
	double x,y;
	Point(double x=0,double y=0) :x(x),y(y){}
};

typedef Point Vector;
Vector operator +(Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}
Vector operator -(Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}
Vector operator *(Vector A,double p){return Vector(A.x*p,A.y*p);}
Vector operator /(Vector A,double p){return Vector(A.x/p,A.y/p);}

bool operator <(const Point& a,const Point &b){
	return a.x<b.x || (a.x==b.x && a.y<b.y);
}

const double eps=1e-10;
int dcmp(double x){
	if(fabs(x)<eps) return 0;else return x<0?-1 :1; 
}

bool operator == (const Point &a,const Point &b){
	return dcmp(a.x-b.x)==0 && dcmp(a.y-b.y)==0;}


double dot(Vector A,Vector B){
	return A.x*B.x+A.y*B.y;
}

double length(Vector A){return sqrt(dot(A,A));}
double angle(Vector A,Vector B){
	return acos(dot(A,B)/length(A)/length(B));
}

Vector rotate(Vector A,double rad){          //rad正數時表示逆時針 負數時表示順時針 
	return Vector(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
}



double cross(Vector A,Vector B){
	return A.x*B.y-A.y*B.x;
}

Vector normal(Vector A){
	double l=length(A);
	return Vector(-A.y/l,A.x/l);
}

struct Line{
	Point p;
	Vector v;
	Line(){}
	Line(Point p,Vector v) :p(p),v(v){}
	Point point(double t){return p+v*t;}
};

bool onleft(Line l,Point p){
	return cross(l.v,p-l.p)>0; 
}

double getangle(Vector a){
	return atan2(a.y,a.x);
}

Point getintersection(Line a,Line b){
	Vector u=a.p-b.p;
	double t=cross(b.v,u)/cross(a.v,b.v);
	return a.p+a.v*t;
}

bool cmp(Line a,Line b){
	double c=getangle(a.v),d=getangle(b.v);
	return c<d ? 1:0;
}

Line l[200];
int halfplaneintersection(Line *l,int n,Point *poly){
	sort(l,l+n,cmp);
	int first,last;
	Point *p=new Point[n];   //p[i]爲 q[i]和q[i+1]的交點 
	Line *q=new Line[n];        //雙端隊列 
	q[first=last=0]=l[0];
	for(int i=1;i<n;i++){
		while(first<last && !onleft(l[i],p[last-1])) last--;
		while(first<last && !onleft(l[i],p[first])) first++;
		q[++last]=l[i];
		if(fabs(cross(q[last].v,q[last-1].v))<eps){  //若兩直線平行,取內側的 
			last--;
			if(onleft(q[last],l[i].p)) q[last]=l[i];
			
		}
		if(first<last) p[last-1]=getintersection(q[last-1],q[last]);		
	}
	while(first<last && !onleft(q[first],p[last-1])) last--;
	if(last-first<=1) return 0;
	p[last]=getintersection(q[last],q[first]);
	
	int m=0;
	for(int i=first;i<=last;i++) poly[m++]=p[i];
	return m;
}



Point p[200],poly[200];

Vector v[200],v2[200];
int main(){
	int n;
	while(scanf("%d",&n)==1 && n){
		int m,x,y;
		for(int i=0;i<n;i++){scanf("%d%d",&x,&y); p[i]=Point(x,y);}
		for(int i=0;i<n;i++){
			v[i]=p[(i+1)%n]-p[i];
			v2[i]=normal(v[i]);
		}
		double left=0,right=20000;
		while(right-left>1e-6){
			double mid=left+(right-left)/2;
			for(int i=0;i<n;i++) l[i]=Line(p[i]+v2[i]*mid,v[i]);
			m=halfplaneintersection(l,n,poly);
			if(!m) right=mid;else left=mid;
		}
		printf("%.6lf\n",left);
	
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章