• HDU3644 2010 Asia Regional Hangzhou Site Online Contest D A Chocolate Manufacturer's Problem


    1、判断多边形有向边顺、逆时针:

    取最右点p[i],p[i-1]->p[i]与p[i]->p[i+1]成右手关系则为逆时针。

    2、判断点与简单多边形位置关系:

    参考文献:王学军,沈连婠,朱绍源等.基于左边的点在简单多边形内的判别算法[J].机械工程师,2006,(2):53-54.

    给定一个简单多边形,判别点u在多边形G内外的判断算法步骤:
    Step1:过u作一水平射线;
    Step2:求出射线与简单多边形G的交点;
    Step3:若交点为0,则u在G外,结束;
    Step4:若交点数大于0,求出与u点距离最近交点v;
    Step5:找到交点v所在边的两顶点,记p1为p[i],p2为p[i+1];
    Step6:判断交点v是否是顶点,若v与p[i]重合,则p1为p[i-1],若v与p[i+1]重合,则p2为p[i+2];
    Step7:判断 vu 到 vp1 沿逆时针方向的角度是否小于 vp2到vp1沿逆时针方向的角度,若是,则u在G内,否则在外,结束。
     
    3、模拟退火,在边上选采样点可避免直接采样到多边形外,其他方面在方法上没有特别之处。参数调整比较纠结,改天编译器变了或者HDU数据变了这代码就不一定能AC了。
     
      1 #include<stdio.h>
      2 #include<string.h>
      3 #include<stdlib.h>
      4 #include<math.h>
      5 #include<time.h>
      6 const int maxn = 55;
      7 const double eps = 1e-8;
      8 const double pi = acos(-1.0);
      9 int dcmp(double x)
     10 {
     11     if(x > eps) return 1;
     12     return x < -eps ? -1 : 0;
     13 }
     14 inline double min(double a, double b)
     15 {return a < b ? a : b;}
     16 inline double max(double a, double b)
     17 {return a > b ? a : b;}
     18 inline double Sqr(double x)
     19 {return x * x;}
     20 /**************************************************/
     21 //点及关于点、线的操作 
     22 struct Point
     23 {
     24     double x, y;
     25     Point(){x = y = 0;}
     26     Point(double a, double b)
     27     {x = a, y = b;}
     28     inline Point operator-(const Point &b)const
     29     {return Point(x - b.x, y - b.y);}
     30     inline Point operator+(const Point &b)const
     31     {return Point(x + b.x, y + b.y);}
     32     inline Point operator-()
     33     {return Point(-x, -y);}
     34     inline Point operator*(const double &b)const
     35     {return Point(x * b, y * b);}
     36     inline double dot(const Point &b)const
     37     {return x * b.x + y * b.y;}
     38     inline double cross(const Point &b, const Point &c)const
     39     {return (b.x - x) * (c.y - y) - (c.x - x) * (b.y - y);}
     40     inline double Dis(const Point &b)const
     41     {return sqrt((*this - b).dot(*this - b));}
     42     inline bool operator<(const Point &b)const
     43     {
     44         if(!dcmp(x - b.x)) return y < b.y;
     45         return x < b.x;
     46     }
     47     inline bool operator>(const Point &b)const
     48     {return b < *this;}
     49     inline bool operator==(const Point &b)const
     50     {return !dcmp(x - b.x) && !dcmp(y - b.y);}
     51     inline bool InLine(const Point &b, const Point &c)const
     52     {return !dcmp(cross(b, c));}
     53     inline bool OnSeg(const Point &b, const Point &c)const//包括端点
     54     {return InLine(b, c) && (*this - c).dot(*this - b) < eps;}
     55     inline bool InSeg(const Point &b, const Point &c)const//不包括端点
     56     {return InLine(b, c) && (*this - c).dot(*this - b) < -eps;}
     57     double ToSeg(const Point&, const Point&)const;
     58 };
     59 /**************************************************/
     60 bool Parallel(const Point &a, const Point &b, const Point &c, const Point &d)
     61 {return !dcmp(a.cross(b, a + d - c));}
     62 Point LineCross(const Point &a, const Point &b, const Point &c, const Point &d)
     63 {
     64     double u = a.cross(b, c), v = b.cross(a, d);
     65     return Point((c.x * v + d.x * u) / (u + v), (c.y * v + d.y * u) / (u + v));
     66 }
     67 double Point::ToSeg(const Point &b, const Point &c)const
     68 {
     69     Point t(x + b.y - c.y, y + c.x - b.x);
     70     if(cross(t, b) * cross(t, c) > eps)
     71         return min(Dis(b), Dis(c));
     72     return Dis(LineCross(*this, t, b, c));
     73 }
     74 bool SegCross(const Point &a, const Point &b, 
     75         const Point &c, const Point &d, Point &p)//包括端点
     76 {
     77     if(Parallel(a, b, c, d)) return false;
     78     if(a.cross(b, c) * a.cross(b, d) <= 0 && c.cross(d, a) * c.cross(d, b) <= 0)
     79     {
     80         p = LineCross(a, b, c, d);
     81         return true;
     82     }
     83     return false;
     84 }
     85 /**************************************************/
     86 Point p[maxn];
     87 int n;
     88 double r;
     89 /**************************************************/
     90 double AngCounterClock(double start, double end)
     91 {return end - start + (end > start - eps ? 2 * pi : 0);}
     92 bool InSimplePolygon(Point u, Point p[], int n/*double neg_inf*/)
     93 //判断点在简单多边形内,不包括边界,多边形点为逆时针
     94 {
     95     double neg_inf = -1e20, angvu, angvp1, angvp2;
     96     Point v(0, u.y), p1, p2, tmp;
     97     int i, id;//距离u最近交点对应线段起始点id
     98     bool flag = false;
     99     p[n] = p[0];
    100     //设u->v为水平负向射线
    101 /*    for(i = 0, neg_inf = 0; i < n; ++ i) neg_inf = min(neg_inf, p[i].x);
    102     neg_inf -= 100.0;    */
    103     v.x = neg_inf;
    104     for(i = 0; i < n; ++ i)
    105     {
    106         if(u.OnSeg(p[i], p[i + 1])) return false;
    107         if(!SegCross(u, v, p[i], p[i + 1], tmp)) continue;
    108         flag = true;
    109         if(tmp.x - v.x > eps) v.x = tmp.x, id = i;
    110     }
    111     if(!flag) return false;
    112     p1 = v == p[id] ? p[(id + n - 1) % n] : p[id];
    113     p2 = v == p[id + 1] ? p[(id + 2) % n] : p[id + 1];
    114     angvu = atan2(u.y - v.y, u.x - v.x);
    115     angvp1 = atan2(p1.y - v.y, p1.x - v.x);
    116     angvp2 = atan2(p2.y - v.y, p2.x - v.x);
    117     return AngCounterClock(angvu, angvp1) < 
    118         AngCounterClock(angvp2, angvp1) - eps;
    119 }
    120 /**************************************************/
    121 double PtoPolygon(Point u, Point p[], int n)//点到多边形边、点的最近距离 
    122 {
    123     int i;
    124     double res = 1e120;
    125     p[n] = p[0];
    126     for(i = 0; i < n; ++ i)
    127         res = min(res, u.ToSeg(p[i], p[i + 1]));
    128     return res;
    129 }
    130 /**************************************************/
    131 //模拟退火
    132 const int maxsam = 20;
    133 const int pacelen = 5;
    134 const double depace = 0.57;
    135 const double endeps = 1e-3;
    136 Point sam[maxsam];
    137 double mindis[maxsam];
    138 bool SA(double r)
    139 {
    140     int i, j, samnum;
    141     Point tmp;
    142     double tmpdis;
    143     double maxx = -1e30, maxy = -1e30, minx = 1e30, miny = 1e30;
    144     for(i = 0; i < n; ++ i)
    145     {
    146         maxx = max(p[i].x, maxx);
    147         maxy = max(p[i].y, maxy);
    148         minx = min(p[i].x, minx);
    149         miny = min(p[i].y, miny);
    150     }
    151     samnum = maxsam < n ? maxsam : n;
    152     double pace = sqrt(Sqr(maxx - minx) + Sqr(maxy - miny));
    153     for(i = 0; i < samnum; ++ i)//随机选边,随机比例选择边上的点作为采样点 
    154     {
    155         j = rand() % n;
    156         sam[i] = p[j] + (p[j + 1] - p[j]) * (rand() / 32767.0);
    157         mindis[i] = 0;
    158     }
    159     for(; pace > endeps; pace *= depace)
    160         for(i = 0; i < samnum; ++ i)
    161             for(j = 0; j < pacelen; ++ j)
    162             {
    163                 tmp.x = sam[i].x + cos((double)rand()) * pace;
    164                 tmp.y = sam[i].y + cos((double)rand()) * pace;
    165                 if(!InSimplePolygon(tmp, p, n)) continue;
    166                 tmpdis = PtoPolygon(tmp, p, n);
    167                 if(tmpdis > r - endeps) return true;
    168                 if(tmpdis > mindis[i])
    169                 {
    170                     sam[i] = tmp;
    171                     mindis[i] = tmpdis;
    172                 }
    173             }
    174     return false;
    175 }
    176 /**************************************************/
    177 void MakeCounterClock(Point p[], int n)//顺时针则反转多边形的有向边 
    178 {
    179     int i, id = 0;
    180     p[n] = p[0];
    181     for(i = 0; i < n; ++ i) if(p[i].x > p[id].x) id = i;
    182     if(p[id].cross(p[id + 1], p[(id + n - 1) % n]) > eps) return;
    183     Point tmp;
    184     for(i = n - 1 >> 1; i >= 0; -- i)
    185         tmp = p[i], p[i] = p[n - i - 1], p[n - i - 1] = tmp;
    186 }
    187 int main()
    188 {
    189     srand(419);
    190     while(scanf("%d", &n) && n)
    191     {
    192         for(int i = 0; i < n; ++ i)
    193             scanf("%lf%lf", &p[i].x, &p[i].y);
    194         MakeCounterClock(p, n);
    195         scanf("%lf", &r);
    196         printf(SA(r) ? "Yes\n" : "No\n");
    197     }
    198     return 0;
    199 }
  • 相关阅读:
    【Unity学习笔记】Unity网络游戏开发实战(一)---网络编程的开端:Echo程序
    【DX11学习笔记】GerstnerWave波浪模拟(基于GPU计算着色器的实现)
    【DX11学习笔记】粒子系统--爆炸特效
    【设计模式】(二)观察者模式是什么?
    【设计模式】(一)工厂模式是什么?
    【C++笔记】C++中常见智能指针auto_ptr、unique_ptr、shared_ptr和weak_ptr的用法
    【C++笔记】C++关联容器set和map的概述和操作
    【C++笔记】C++函数模版与类模版
    【C++笔记】C++中vector、stack、deque、list的简易实际使用方法
    python之赋值、浅拷贝、深拷贝
  • 原文地址:https://www.cnblogs.com/CSGrandeur/p/2673873.html
Copyright © 2020-2023  润新知