HDU 5033

题意: 给你 N 楼房, 然后给你m个人站在这些楼房之间, 问看到天空的仰角是多少度

思路: 对于每一个人, 算出左边的凸包, 和右边的凸包, 找出最大斜率点, 算角度即可

(我在线算比较费时, 离线可以省时间)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const double INF=2e9;
const int maxn = 1e5 + 131;
const double PI = acos(-1.0);
const double eps = 1e-8;
struct Point
{
    double x, y;
    int pos;
    Point(int x = 0,int y = 0): x(x), y(y) {}
    //Point(){}
};

int dcmp(double x)
{
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    else return 1;
}

typedef Point Vector;
Vector operator + (Vector A, Vector B) { return Vector(A.x+B.x, A.y+B.y); }
Vector operator - (Point  A, Point  B) { return Vector(A.x-B.x, A.y-B.y); }
bool operator < (Point A, Point B) { return A.x < B.x; }
int Cross(Vector A, Vector B) { return dcmp(A.x*B.y - A.y*B.x); }
double Dot(Vector A, Vector B) { return double(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)); }

Point p[maxn], ch[maxn];
int PreL[maxn], PreR[maxn];

void ConVexHull(Point *p, int n, Point *ch)
{
    int m = 0;
    PreL[0] = 0;
    for(int i = 0; i < n; ++i) {
        while(m > 1 && dcmp(Cross(ch[m-1] - ch[m-2], p[i]-ch[m-2]) > 0)) m--;
        ch[m++] = p[i];
        if(i) PreL[i] = ch[m-2].pos;
    }
    m = 0;
    PreR[n-1] = n-1;
    for(int i = n-1; i >= 0; --i) {
        while(m > 1 && dcmp(Cross(ch[m-1] - ch[m-2], p[i]-ch[m-2]) < 0)) m--;
        ch[m++] = p[i];
        if(n-1-i) PreR[i] = ch[m-2].pos;
    }
}
int lb(double xx,int n)
{
    int left = 0, right = n;
    p[n].x = INF;
    while(left < right)
    {
        int mid=(left+right)>>1;
        if(xx<p[mid].x)
            right=mid;
        else
            left=mid+1;
    }
    return left-1;
}


int main()
{
    int t;
    scanf("%d",&t);
    for(int kase = 1; kase <= t; ++kase)
    {
        int n;
        scanf("%d",&n);
        for(int i = 0; i < n; ++i)
        {
            scanf("%lf%lf", &p[i].x, &p[i].y);
        }
        sort(p,p+n);
        for(int i = 0; i < n; ++i) p[i].pos = i;
        ConVexHull(p,n,ch);
        /*for(int i = 0; i < n; ++i)
            cout << PreL[i] << " ";
            cout <<endl;
        for(int i = 0; i < n; ++i)
            cout << PreR[i] << " ";
            cout <<endl;*/
        int Q; double pos;
        scanf("%d",&Q);
        printf("Case #%d:\n",kase);
        while(Q--)
        {
            scanf("%lf",&pos);
            int lll = lb(pos,n);
            int rrr = lll + 1;
            Point New(pos, 0);
            /*cout << New.x << "   " << New.y <<endl;
            cout << p[lll].x << "  " << p[lll].y << endl;
            cout << p[rrr].x << "  " << p[rrr].y << endl;
            cout << "***********************\n";
            cout << p[PreL[lll]].x << "  " << p[PreL[lll]].y <<endl;
            cout << p[n-PreR[rrr]-1].x << "  " << p[n-1-PreR[rrr]].y <<endl;*/
            Vector L, R;
            while(dcmp(Cross(p[lll]-New, p[PreL[lll]]-New) < 0)) lll = PreL[lll];
            L = p[lll]-New;

            while(dcmp(Cross(p[rrr]-New, p[PreR[rrr]]-New) > 0)) rrr = PreR[rrr];
            R = p[rrr] - New;

            //cout << "L : \n" << L.x << "  " << L.y<< endl;
            //cout << "R : \n" << R.x << "  " << R.y<< endl;
            double Degree = fabs(Angle(L,R)*180 / PI);
            printf("%.10f\n",Degree);
        }
    }
}

  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值