3 3 1 2 2 1 5 1 1 4 3 1 3 2 2 5 1 1 4 3 1 4 2 3 5 1 1 4
Case #1: 101.3099324740 Case #2: 90.0000000000 Case #3: 78.6900675260
给出一些房子的坐标和高度,询问一些坐标,输出这个坐标能看见天空的角度。
把询问点当成坐标为x高度为0的房子,和别的房子一起按x坐标排序。先从左到右扫一遍,栈中存斜率不增的点,也就是发现K(stk[rear-1],stk[rear])<K(stk[rear],i)就退栈,再把i这个点加入栈中,并记录栈顶元素在左边挡住了i。因为被退掉的点是肯定不会挡住视线的。同理从右到左扫一遍,栈中存斜率不减的点,同样的方法记住右边挡住i的是第几个房子。最后对于每个询问,根据左边挡住它的房子和右边挡住它的房子计算角度。
#include<iostream> #include<algorithm> #include<queue> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<set> #include<map> #define INF 0x3f3f3f3f #define MAXN 200010 #define MAXM 110 #define MOD 1000000007 #define MAXNODE 4*MAXN #define eps 1e-9 #define pi (4*atan(1.0)) using namespace std; typedef long long LL; int T,N,Q,stk[MAXN]; struct Point{ double x,h,ans; int l,r,id; bool operator < (const Point& rhs) const{ return id<rhs.id; } }p[MAXN]; bool cmp(Point a,Point b){ return a.x<b.x; } double K(int a,int b){ return (p[a].h-p[b].h)/(p[a].x-p[b].x); } void solve1(){ int rear=0; stk[0]=0; for(int i=1;i<N;i++){ while(rear&&K(stk[rear-1],stk[rear])<K(stk[rear],i)) rear--; p[i].l=p[stk[rear]].id; stk[++rear]=i; } } void solve2(){ int rear=0; stk[0]=N-1; for(int i=N-2;i>=0;i--){ while(rear&&K(stk[rear-1],stk[rear])>K(stk[rear],i)) rear--; p[i].r=p[stk[rear]].id; stk[++rear]=i; } } double cal(double x1,double y1,double x2,double y2){ return 180*(atan2(y1,x1)-atan2(y2,x2))/pi; } int main(){ freopen("in.txt","r",stdin); scanf("%d",&T); int cas=0; while(T--){ p[0].h=p[0].id=0; p[0].x=-1; scanf("%d",&N); int n=N; for(int i=1;i<=N;i++){ scanf("%lf%lf",&p[i].x,&p[i].h); p[i].id=i; } scanf("%d",&Q); for(int i=1;i<=Q;i++){ scanf("%lf",&p[N+i].x); p[N+i].h=0; p[N+i].id=N+i; } p[N+Q+1].x=10000000000; p[N+Q+1].h=0; p[N+Q+1].id=N+Q+1; N=N+Q+2; sort(p,p+N,cmp); solve1(); solve2(); sort(p,p+N); printf("Case #%d:\n",++cas); for(int i=n+1;i<=n+Q;i++) printf("%.10lf\n",cal(p[p[i].l].x-p[i].x,p[p[i].l].h,p[p[i].r].x-p[i].x,p[p[i].r].h)); } return 0; }