题目链接:
LightOJ 1203 Guarding Bananas
题意:
给出n个点,找到一个点使从这个点看其他所有点所形成的最大夹角最小(视野内能看完其他所有点)。
分析:
先求个凸包,因为这样的点肯定是凸包上的点。然后枚举凸包顶点,凸包顶点和相邻边的另外两个端点所形成的角
肯定能覆盖所有凸包顶点,这样子一来就是转化为求两点对一点所形成的夹角,枚举取最小即可。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <climits>
#include <iostream>
using namespace std;
const int MAX_N=101000;
const double INF=1e90;
const double eps=1e-10;
const double PI=acos(-1.0);int T,n,cases = 0;struct Point{double x,y;Point () {}Point (double x,double y) : x(x),y(y) {}Point operator + (const Point& rhs) const {return Point(x+rhs.x,y+rhs.y);}Point operator - (const Point& rhs) const {return Point(x-rhs.x,y-rhs.y);}Point operator * (const double d) const {return Point(d*x,d*y);}double dis(const Point& rhs) const { //两点距离return sqrt((x-rhs.x)*(x-rhs.x)+(y-rhs.y)*(y-rhs.y));}double dot(const Point& rhs) const { //点积、内积return (x*rhs.x+y*rhs.y);}double cross(const Point& rhs) const { //叉积、外积return (x*rhs.y-y*rhs.x);}double rad(const Point& a, const Point& b) const {Point p = *this;return fabs(atan2(fabs((a - p).cross(b - p)), (a - p).dot(b - p)));}
}point[MAX_N],vertex[MAX_N];inline bool cmp_x(const Point a,const Point b)
{if(a.x==b.x) return a.y<b.y;return a.x<b.x;
}inline int Andrew()
{sort(point,point+n,cmp_x);int k=0;for(int i=0;i<n;i++){while(k>1&&(vertex[k-1]-vertex[k-2]).cross(point[i]-vertex[k-1])<=0){k--;}vertex[k++]=point[i];}int m = k;for(int i=n-2;i>=0;i--){ while(k>m&&(vertex[k-1]-vertex[k-2]).cross(point[i]-vertex[k-1])<=0){k--;}vertex[k++]=point[i];}if(k>1) k--; return k;
}int main()
{scanf("%d", &T);while(T--){scanf("%d", &n);for(int i = 0; i < n; i++){scanf("%lf%lf", &point[i].x, &point[i].y);}printf("Case %d: ", ++cases);int total = Andrew();if(total == 1 || total == 2){printf("%.6lf\n", 0);continue;}double ans = 400;vertex[total] = vertex[0];for(int i = 0; i < total; i++){int pre = (i - 1 + total) % total;int nxt = (i + 1 + total) % total;double tmp = vertex[i].rad(vertex[pre], vertex[nxt]);ans = min(ans, tmp);}printf("%.6lf\n", ans / PI * 180.0);}
}