zoukankan      html  css  js  c++  java
  • Are You Safe? Gym

    题意:给你n个坐标点,围成一个多边形,之后给你m个坐标点,逆时针输出点,询问你该点是否在凸包内(不包含点和边上)。

    思路:计算几何,运用Graham逆时针排序输出,然后判断该点是否在内就行。

    #include <iostream>
    #include <string.h>
    #include <string>
    #include <math.h>
    #include <stdlib.h>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <stack>
    #include <algorithm>
    using namespace std;
    #define ll long long
    #define N 100005
    #define eps 0.00000001//偏差值1e8
    #define pi acos(-1.0)//高精度圆周率
    #define fori for(i=0;i<n;i++)
    #define fori1 for(i=1;i<=n;i++)
    const int maxp = 1010;                    //点的数量
    int sgn(double x){                        //判断x是否等于0
        if (fabs(x) < eps) return 0;
        else return x < 0 ? -1 : 1;
    }
    //定义点及其基本运算
    struct Point {
        double x, y;
        Point() {}    
        Point(double x, double y) :x(x), y(y) {}
        Point operator + (Point B) { return Point(x + B.x, y + B.y); }
        Point operator - (Point B) { return Point(x - B.x, y - B.y); }
        bool operator ==(Point B) { return sgn(x - B.x) == 0 && sgn(y - B.y) == 0; }
        bool operator <(Point B)                                                    //比较两个点,用于凸包计算
        {
            return sgn(x - B.x) < 0 || (sgn(x - B.x) == 0 && sgn(y - B.y) < 0);
        }
    };
    Point s[10005],g[10005],h[10005];
    typedef Point Vector;                                                        //定义向量
    double Dot(Vector A, Vector B) { return A.x * B.x + A.y * B.y; }            //点积
    double Cross(Vector A, Vector B) { return A.x * B.y - A.y * B.x; }            //叉积
    struct Line {                                                                //线上的两个点
        Point p1, p2;
        Line(){}
        Line(Point p1,Point p2):p1(p1),p2(p2){}
        Line(Point p, double angle)
        {
            p1 = p;
            if (sgn(angle - pi / 2) == 0) { p2 = (p1 + Point(0, 1)); }
            else { p2 = (p1 + Point(1, tan(angle))); }
        }
    };                                                                            
    double mult(Point a, Point b, Point o) {                            /////计算叉乘 ao 和 bo
        return (a.x - o.x) * (b.y - o.y) >= (b.x - o.x) * (a.y - o.y);
    }
    int Graham(Point p[], int n, Point res[]) {                                    //逆时针排序,构造凸包形状
        int top = 1;
        sort(p, p + n);
        if (n == 0) return 0;
        res[0] = p[0];
        if (n == 1) return 0;
        res[1] = p[1];
        if (n == 2) return 0;
        res[2] = p[2];
        for (int i = 2; i < n; i++) {
            while (top && (mult(p[i], res[top], res[top - 1])))
                top--;
            res[++top] = p[i];
        }
        int len = top;
        res[++top] = p[n - 2];
        for (int i = n - 3; i >= 0; i--) {
            while (top != len && (mult(p[i], res[top], res[top - 1])))
                top--;
            res[++top] = p[i];
        }
        return top;
    }
    struct Polygon
    {
        int n;                                                //多边形的顶点数
        Point p[maxp];                                        //多边形的点
        Line v[maxp];                                        //多边形的边
    };
    //点和线段的关系:0为点p不在线段v上;1为点p在线段v上
    bool Point_on_seg(Point p, Line v)                                            
    {
        return sgn(Cross(p - v.p1, v.p2 - v.p1)) == 0 && sgn(Dot(p - v.p1, p - v.p2)) <= 0;
    }
    //判断点和任意多边形的关系:3为点上;2为边上;1为内部;0为外部
    int Point_in_polygon(Point pt, Point* p, int n)
    {
        int i;
        for (i = 0; i < n; i++) {
            if (p[i] == pt)return 3;
        }
        for (i = 0; i < n; i++) 
        {
            Line v = Line(p[i],p[(i + 1) % n]);
        if (Point_on_seg(pt, v))return 2;
        }
        int num = 0;
        for (int i = 0; i < n; i++)
        {
            int j = (i + 1)%n;
            int c = sgn(Cross(pt - p[j], p[i] - p[j]));
            int u = sgn(p[i].y - pt.y);
            int v = sgn(p[j].y - pt.y);
            if (c > 0 && u < 0 && v >= 0)num++;
            if (c < 0 && u >= 0 && v < 0)num--;
        }
        return num != 0;
    }
    int main()
    {
        
        ll book[10005];
        ll i, j, k;
        ll n,t,m;
        ll sum = 0, ret = 0,ret2=0;
        ll ans = 0;
        ll flag = 1;
        ll d;
        cin >> t;
        while (t--)
        {
            
            cin >> n >> m;
            fori
                cin >> s[i].x >> s[i].y;
            n = Graham(s, n, h);
            //cout << n << endl;
            for (i = 0; i < m; i++)
                cin >> g[i].x >> g[i].y;
            if (ret)
                cout << endl;
            cout << "Case " << ++ret << endl;
            fori
                printf("%.0lf %.0lf
    ", h[i].x, h[i].y);
            printf("%.0lf %.0lf
    ", h[0].x, h[0].y);
            for (i = 0; i < m; i++)
            {
                if (!Point_in_polygon(g[i], h, n))//在外部
                    cout << g[i].x << " " << g[i].y << " is safe!" << endl;
                else//在内部
                    cout << g[i].x << " " << g[i].y << " is unsafe!" << endl;
    
            }
        }
    
        
    }
  • 相关阅读:
    python构造一个freebuf新闻发送脚本
    CISCO路由器练习
    python dns欺骗
    心脏滴血漏洞
    0CTF题中的神奇宝贝WP
    一套海量在线用户的移动端IM架构设计实践分享(含详细图文)(转)
    sendfile函数--零拷贝(转)
    浅谈分布式消息技术 Kafka(转)
    架构之微服务(zookeeper)转
    Zookeeper 3、Zookeeper工作原理(转)
  • 原文地址:https://www.cnblogs.com/ch-hui/p/12628227.html
Copyright © 2011-2022 走看看