zoukankan      html  css  js  c++  java
  • hrbustoj 1429:凸多边形(计算几何,判断点是否在多边形内,二分法)

    凸多边形

    Time Limit: 2000 MS    Memory Limit: 65536 K

    Total Submit: 130(24 users)   Total Accepted: 40(18 users)       Rating:         Special Judge: No

    Description

    已知一个凸多边形A(包含n个点,点按照顺时针给出),和一个点集B(包含m个点),请判断这m个点是否都严格在凸多边形A内部。

    Input

    输入包含多组测试数据。

    对于每组测试数据:

    第1行,包含一个整数n (3 ≤ n ≤ 105)代表着凸多边形A的点的数量。

    接下来n行每行包含一个坐标(x, y) (-109 ≤ x, y ≤ 109) 表示这个凸多边形,点按照顺时针给出。

    第n + 2行,包含一个整数m (3 ≤ m ≤ 105)代表着点集B的点的数量。

    接下来m行每行包含一个坐标(x, y) (-109 ≤ x, y ≤ 109) 表示这个点集B。

    处理到文件结束

    Output

    对于每组测试数据:

    第1行,如果点集B都严格在凸多边形A内,输出YES,否则输出NO。

    Sample Input

    4

    -10 -10

    -10 10

    10 10

    10 -10

    3

    0 0

    1 1

    2 2

    4

    -10 -10

    -10 10

    10 10

    10 -10

    3

    100 100

    1 1

    2 2

    Sample Output

    YES

    NO

    Author

    齐达拉图@HRBUST


      计算几何,判断点是否在多边形内(二分法)

      判断点是否在多边形内有多种方法,例如:射线法,角度和判断法,弧长法,二分法。

      射线法是我最开始学的方法,较麻烦;角度和判断法也叫转角法,比较方便,但是由于要计算大量的反三角函数,所以速度较慢,容易产生精度误差。而弧长法的优点恰恰就是精度高,只需作乘法和减法,若对整数坐标则完全没有精度问题。而且实现简单,比射线法和转角法都好写。二分法速度最快,特别适应于判断多个点是否在多边形内的情况。就像这道题。

      其中前三种方法时间复杂度都是O(n),二分法时间复杂度是O(logn)

      这道题的题意是已知构成凸多边形A的n个点的坐标,和点集B的m个点的坐标,求这B的m个点是否都在凸多边形A内(严格内部,就是点不能在多边形边上)。

      思路:用以上前三种方法的任意一种都会超时,时间复杂度为(O(mn)),遂使用二分法,这道题的时间复杂度为(O(mlogn))。

      二分法求多边形的步骤:

      1、选择多边形其中一个点为起点,连接其它点作射线。

      2、判断给定的点是否在所有射线包围的区域之内,即判断给定点是否在最左侧射线的左边,或者在最右侧射线的右边。

      3、如果在射线包围的区域之内,选择构成最两侧的射线的点为left和right,则mid = (left+right)/2,连接给顶点和起点作射线,判断该射线在mid点和起点的哪一边,不断循环,如此用二分法最后求出给定点所在的三角形区域,由此确定了除起点外的一条边。

      4、判断给定点在这条边的左方还是右方,由此判断给定点是否在三角形区域内,也就是是否在多边形内。

      注意:这道题有个坑,点要求严格在多边形内部,也就是说不能在多边形的边上。注意这一点,测试数据控制的很严格,WA了好多次才明白过来。

      代码

     1 #include <stdio.h>
     2 #define eps 1e-10
     3 struct Point{
     4     double x,y;
     5 };
     6 double xmulti(Point p1,Point p2,Point p0)    //求p1p0和p2p0的叉积,如果大于0,则p1在p2的顺时针方向
     7 {
     8     return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
     9 }
    10 Point A[100001],B[100001];
    11 int main()
    12 {
    13     int i,n,m;
    14     while(scanf("%d",&n)!=EOF){
    15         for(i=1;i<=n;i++)    //输入多边形的顶点
    16             scanf("%lf%lf",&A[i].x,&A[i].y);
    17         scanf("%d",&m);
    18         for(i=1;i<=m;i++)    //输入点集
    19             scanf("%lf%lf",&B[i].x,&B[i].y);
    20         //二分法判断B上的点是否在原凸多边形A内,注意在边上不行
    21         for(i=1;i<=m;i++){    //B[i]
    22             if(xmulti(B[i],A[2],A[1])<=eps || xmulti(B[i],A[n],A[1])>=-eps)    //在第一个点为起点的扇形之外或在边上
    23                 break;
    24             int left=2,right=n;
    25             while(right-left!=1){
    26                 int mid = (left+right)/2;
    27                 if(xmulti(B[i],A[mid],A[1])>eps)
    28                     left = mid;
    29                 else 
    30                     right = mid;
    31             }
    32             if(xmulti(B[i],A[right],A[left])<=eps)    //在边之外或在边上
    33                 break;
    34         }
    35         if(i>m)
    36             printf("YES
    ");
    37         else
    38             printf("NO
    ");
    39     }
    40     return 0;
    41 }

    Freecode : www.cnblogs.com/yym2013

  • 相关阅读:
    asp.net core 自定义401和异常显示内容(JWT认证、Cookie Base认证失败显示内容)
    asp.net core 微信APP支付(扫码支付,H5支付,公众号支付,app支付)之4
    asp.net core 支付宝支付( 电脑2.0)
    asp.net core 微信公众号支付(扫码支付,H5支付,公众号支付,app支付)之3
    asp.net core 微信获取用户openid
    asp.net core 微信H5支付(扫码支付,H5支付,公众号支付,app支付)之2
    asp.net core 微信扫码支付(扫码支付,H5支付,公众号支付,app支付)之1
    论BOM管理的若干重要问题
    BOM的编制与管理
    设计变更时,零部件的标识是变号还是升版?
  • 原文地址:https://www.cnblogs.com/yym2013/p/3673616.html
Copyright © 2011-2022 走看看