LightOJ 1203--Guarding Bananas(二维凸包+内角计算)

1203 - Guarding Bananas

   PDF (English) Statistics Forum
Time Limit: 3 second(s) Memory Limit: 32 MB

Once there was a lazy monkey in a forest. But he loved banana too much. One day there was a storm in the jungle and all the bananas fell from the trees. The monkey didn‘t want to lose any of the bananas. So, he wanted to find a banana such that he can eat that and he can also look after the other bananas. As he was lazy, he didn‘t want to move his eyes too wide. So, you have to help him finding the banana from where he can look after all the bananas but the degree of rotating his eyes is as small as possible. You can assume that the position of the bananas can be modeled as 2D points.

Here a banana is shown, from where the monkey can look after all the bananas with minimum eye rotation.

Input

Input starts with an integer T (≤ 13), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 105) denoting the number of bananas. Each of the next n lines contains two integers x y (-109 ≤ x, y ≤ 109) denoting the co-ordinate of a banana. There can me more than one bananas in the same co-ordinate.

Output

For each case, print the case number and the minimum angle in degrees. Errors less than 10-6 will be ignored.

Sample Input

Output for Sample Input


2

1

4 4

4

0 0

10 0

10 10

2 1


Case 1: 0

Case 2: 45.0000000

Note

Dataset is huge. Use faster I/O methods.

  • 题意:在所有给定的香蕉中找到一个香蕉,使得从这个香蕉看向其他香蕉的角度尽可能小的同时看到的香蕉数目尽可能多。
  • 由于香蕉可以化为半径忽略不计的二维平面上的点,所以可以想到,站在这些点的凸包的顶点处看过去的角度小并且看到的点更多,否则,总可以向这些定顶点处移动,使得看到的点更多或者角度更小。
  • 所以这道题就是求其凸包,然后找到里面最小的那个内角。
  •  1 #include<iostream>
     2 #include<algorithm>
     3 #include<cmath>
     4 #include<cstdio>
     5 #include<cstring>
     6 using namespace std;
     7 const int maxn = 1e5 + 5;
     8 const double pi = acos(-1.0);
     9 const double eps = 1e-8;
    10 int sgn(double x) {
    11     if (fabs(x) < eps)return 0;
    12     if (x < 0)return -1;
    13     else return 1;
    14 }
    15 typedef struct point {
    16     double x, y;
    17     point() {
    18
    19     }
    20     point(double a, double b) {
    21         x = a;
    22         y = b;
    23     }
    24     point operator -(const point &b) const {
    25         return point(x - b.x, y - b.y);
    26     }
    27     double operator *(const point &b)const {
    28         return x*b.x + y*b.y;
    29     }
    30     double operator ^(const point &b)const {    //叉乘
    31         return x*b.y - y*b.x;
    32     }
    33     bool operator <(point b)const {
    34         return sgn(x - b.x) == 0 ? sgn(y - b.y)<0 : x<b.x;
    35     }
    36     //返回pa,pb的夹角,该点看a,b的夹角,弧度制
    37     //弧度=度×π/180°
    38     //度=弧度×180°/π
    39     double rad(point a, point b) {
    40         point p = *this;
    41         return fabs(atan2(fabs((a - p) ^ (b - p)), (a - p)*(b - p)));
    42     }
    43 }point;
    44 point p[maxn];
    45 int n = 0, res[maxn];
    46 int top;//top模拟栈顶
    47 bool multi(point p1, point p2, point p0) {  //判断p1p0和p2p0的关系,<0,p1p0在p2p0的逆时针方向,>0,p1p0在p2p0的顺时针方向
    48     return (p1.x - p0.x)*(p2.y - p0.y) >= (p2.x - p0.x)*(p1.y - p0.y);
    49 }
    50 double Graham() {
    51     int i, len;//top模拟栈顶
    52     sort(p, p + n);
    53     top = 1;
    54     //少于3个点也就没有办法形成凸包
    55     if (n == 0)return 0; res[0] = 0;
    56     if (n == 1)return 0; res[1] = 1;
    57     if (n == 2)return 0; res[2] = 2;
    58     for (i = 2; i < n; i++) {
    59         while (top&&multi(p[i], p[res[top]], p[res[top - 1]]))    //如果当前这个点和栈顶两个点构成折线右拐了,就回溯到上一个点
    60             top--;                                                //弹出栈顶
    61         res[++top] = i;                                           //否则将这个点入栈
    62     }
    63     len = top;
    64     res[++top] = n - 2;
    65     for (i = n - 3; i >= 0; i--) {
    66         while (top != len&&multi(p[i], p[res[top]], p[res[top - 1]]))
    67             top--;
    68         res[++top] = i;
    69     }
    70     double ans =0x3f3f3f;
    71     res[top] = res[0],res[top + 1] = res[1];
    72     for (int i = 1; i <= top; i++) {
    73         ans = min(ans, p[res[i]].rad(p[res[i + 1]], p[res[i - 1]]));
    74     }
    75     return ans / pi * 180;
    76 }
    77 inline int read()
    78 {
    79     int x = 0, f = 1; char ch = getchar();
    80     while (ch<‘0‘ || ch>‘9‘) { if (ch == ‘-‘)f = -1; ch = getchar(); }
    81     while (ch >= ‘0‘&&ch <= ‘9‘) { x = x * 10 + ch - ‘0‘; ch = getchar(); }
    82     return x*f;
    83 }
    84 int main(void) {
    85     int t;
    86     t = read();
    87     for (int cnt = 1; cnt <= t; cnt++) {
    88         cin >> n;
    89         for (int i = 0; i < n; i++) {
    90             p[i].x = read();
    91             p[i].y = read();
    92         }
    93         printf("Case %d: ", cnt);
    94         printf("%.7lf\n", Graham());
    95     }
    96     return 0;
    97 }

原文地址:https://www.cnblogs.com/FlyerBird/p/9557531.html

时间: 2024-10-04 03:01:47

LightOJ 1203--Guarding Bananas(二维凸包+内角计算)的相关文章

【简单凸包】LightOJ 1203 Guarding Bananas

[简单凸包]LightOJ 1203 Guarding Bananas 题目链接:LightOJ 1203 Guarding Bananas 题目大意 构造凸包,求凸包夹角的最小值 笔者的第一道凸包题目,发现Kuangbin的计算几何模板的一个最大缺陷:结构体太长,大空间开不下QAQ 凸包,我的理解是包含已知点集的最小凸集,二维凸包自然可以理解为包含所有点的最小凸多边形. 现在代码的逼格越来越高了~(≧▽≦)/~啦啦啦! 说一下思路 ①Graham's Scan法构建凸包,时间复杂度O(nlog

计算几何 二维凸包问题 Andrew算法

凸包:把给定点包围在内部的.面积最小的凸多边形. Andrew算法是Graham算法的变种,速度更快稳定性也更好. 首先把所有点排序,按照第一关键字x第二关键字y从小到大排序,删除重复点后得到点序列P1...Pn. 1)把P1,P2放入凸包中,凸包中的点使用栈存储 2)从p3开始,当下一个点在凸包当前前进方向(即直线p1p2)左边的时候继续: 3)否则依次删除最近加入凸包的点,直到新点在左边. 如图,新点P18在当前前进方向P10P15的右边(使用叉积判断),因此需要从凸包上删除点P15和P10

使用Graham扫描法求二维凸包的一个程序

1 #include "includeall.h" 2 #include "Link.class.h" 3 4 int RightOrLeft(float x1,float y1,float x2,float y2,float x3,float y3)//判断第三个点在前两个点连成的直线的哪个位置,-1 左边,0,直线上,1 右边 5 { 6 float X=(y3-y1)*(x2-x1)/(y2-y1)+x1; 7 if(X<x3) 8 { 9 return

UVA 10652 Board Wrapping(二维凸包)

传送门 刘汝佳<算法竞赛入门经典>P272例题6包装木板 题意:有n块矩形木板,你的任务是用一个面积尽量小的凸多边形把它们抱起来,并计算出木板占整个包装面积的百分比. 输入:t组数据,每组先输入木板个数n,接下来n行,每行x,y,w,h,j.(x,y)是木板中心的坐标,w是宽,h是高,j是顺时针旋转的角度. 木板互不相交. 输出:对于每组数据,输出木板总面积占包装总面积的百分比,保留小数点后1位. 题解:典型的二维凸包问题,理解并调用模板即可. #include <math.h>

二维凸包模板

double cross(Point a,Point b) { return a.x*b.y-a.y*b.x; } double mul(Point p0,Point p1,Point p2) { return cross(p1-p0,p2-p0); } double dis(Point a) { return sqrt(a.x*a.x+a.y*a.y); } bool cmp(Point a,Point b) { if(dcmp(mul(p[0],a,b))==0) return dis(a-

二维凸包

二维凸包模板 p[1010]//输入的点集,res[1010]//输出的点集 int n;//点的个数 int cmp(Point a,Point b)//先对x坐标排序,在比较y坐标 { if(a.x==b.x) return a.y<b.y; return a.x<b.x; } int ConvexHull()//返回凸包顶点数 { sort(p,p+n,cmp); int m=0; for(int i=0;i<=n-1;i++) { while(m>1&&Cr

二维凸包的板子

二维凸包的板子 感觉没什么可说的,码风抄的孔老师的. #include <cstdio> #include <algorithm> #include <cmath> const int N=1e4+10; #define Point Vector const double eps=1e-8; bool cmp(double a,double b){return fabs(a-b)<eps;} struct Vector { double x,y; Vector()

Luogu 2742 二维凸包

Luogu 2742 二维凸包 使用 \(Andrew\) 算法.将点排序后分别求上下凸壳,用单调栈维护. 利用向量叉积来判断当前方向.若 \(v_1\times v_2<0\) ,说明 \(v_2\) 在 \(v_1\) 的右侧, \(<0\) 为左侧, \(=0\) 说明二者共线. 参考讲解. #include<bits/stdc++.h> using namespace std; #define ll long long #define mp make_pair #defin

【题解】二维凸包

[题解]二维凸包 呵呵呵复习一下这个东西免得做到计算几何连暴力都不会嘤嘤嘤 免得到时候写斜率优化结果凸包不会了嘤嘤嘤 数学走起: \[ \vec{a}=(x_1,y_1),\vec{b}=(x_2,y_2) \shadow_{|\vec{a} \times\vec{b}|}=x_1y_2-x_2y_1 \] 根据右手螺旋定则.\(shadow\)是我乱搞的符号,虽然我搞不懂为什么是这样,但是这个应该和\(\sin(0.5\pi)=1,\sin0=0\)有关,就不纠结了,也比较好记. 遵循\(an