FZU 1918 John’s Direction 解题报告

题意:给出一个点,和一堆边和坐标轴平行的多边形,问由这个点发出的射线不和多边形相交的角度之和。多边形是给出一个起点,然后通过向前走一定的距离和向左向右转90度得到的,且最后一个点是起点
解法:用atan2计算出起点和多边形每条边的极角的大小,然后统计不重叠的角度的大小之和。所得的是会和多边形相交的角度,再用360减就可以。
要注意的地方是,所得的交是小于180°的,如果用atan2计算出两角之差大于pi,则角度应该为(a2,PI)和(-PI,a1);
如果点在多边形边上,要特判。其实直接跳过就可以。
还有一点是有可能出现-0.00所以要取绝对值或者+eps,我就是因为这个wa了六炮
//Memory: 15884 KB		
//Time: 375 MS
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
#include <map>
#include <cmath>
using namespace std;
const int maxn = 1000005;
const int inf = 1111111111;
const double eps = 1e-10;
const double PI = acos(-1.0);
int dx[]={0,-1,0,1},dy[]={1,0,-1,0};
int dcmp(double x)
{
    if(fabs(x)<eps) return 0;
    return x<0?-1:1;
}
struct Point{
    double x,y;
    Point (){};
    Point (double a, double b):x(a),y(b){};
    Point operator + (const Point a){return Point(x+a.x,y+a.y);}
    Point operator - (const Point a){return Point(x-a.x,y-a.y);}
    Point operator * (double c) {return Point(x*c,y*c);}
    Point operator / (double c) {return Point(x/c,y/c);}
	void input(){scanf("%lf%lf",&x,&y);}
	void output(){printf("%.2f %.2f\n",x,y);}
};
typedef Point Vector;
double Cross(Vector a,Vector b)
{
	return a.x*b.y-a.y*b.x;
}
struct Node{
    double x,y;
    Node (){};
    Node (double a, double b):x(a),y(b){};
    bool operator <(const Node&a) const
    {
        return x<a.x||(x==a.x&&y<a.y);
    }
}arg[maxn];
int an;

void Find(Point q, Point p1, Point p2)
{
    double a1,a2;
    if(dcmp(Cross(p1-q,p2-q))==0) return;
    a1 = atan2(p1.y-q.y,p1.x-q.x);
    a2 = atan2(p2.y-q.y,p2.x-q.x);
    if(a2<a1) swap(a1,a2);
    if(a2 - a1 > PI)
    {
        arg[an++] = Node(a2,PI);
        arg[an++] = Node(-PI,a1);
    }
    else arg[an++] = Node(a1,a2);
}
int main()
{
    //freopen("in.txt","r",stdin);
    int cas,n,m,d;
    double len;
    char str[5];
    Point q,p1,p2;
    scanf("%d",&cas);

    for(int ca = 1; ca<=cas; ca++)
    {
        scanf("%d",&n);
        q.input();
        an = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%d",&m);
            p1.input();
            d = 0;
            for(int j = 0; j < m; j++)
            {
                scanf("%s",str);
                //cout<<d<<"***\n";
                if(str[0]=='F')
                {
                    scanf("%lf",&len);
                    p2 = p1 + Point(dx[d],dy[d])*len;
                    Find(q,p1,p2);
                   // p2.output();
                    p1= p2;
                }
                else if(str[0]=='L') d = (d+1)%4;
                else d = (d-1+4)%4;
            }
        }
        //cout<<an<<endl;
        sort(arg,arg+an);
        double ans=0,r,l;
        l = arg[0].x,r = arg[0].y;
        ans+=r-l;
        for(int i = 1; i < an; i++)
        {
            if(dcmp(arg[i].x-r)<0)
            {
                if(dcmp(arg[i].y-r)>0)
                {
                    ans+=arg[i].y-r;
                    r= arg[i].y;
                }
            }
            else
            {
                l = arg[i].x,r = arg[i].y;
                ans+=r-l;
            }
        }
        printf("Case %d: %.2lf\n",ca,(2*PI-ans)/PI*180+eps);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值