usaco 3.4 Closed Fences 计算几何

题目给定一个多边形,要求

1)判断是否简单多边形

方法如下

 

对于临边:假设p1,p2和p2,p3为临边,如果p1,p2,p3重合并且p1,p3在p2的同侧,在存在交叉边,可以通过叉积cross(p1,p2,p3)==0 和点击dot(p1,p2,p3) < 0来判断.

 

对于不相邻的边:如果规范相交,则存在交叉边.

 

2)判断观察者是否能看到,题目的意思是只要能看到一点就满足条件,但是如果线段和观察者共线,则不能看到

 

方法:对于每个顶点p,将其分别做左右微小移动得到点pl,pr, 假设观察者为o,作射线(o,pl)和(o,pr),对于两射线分别求出与其相交并且举例最近的线段,就是能找到观察到的线段

 

 

3)输出要求先按第二点排序,再第一点,实际上,只需要把最后一条线段的两点交换顺序,再把最后两条线段交换顺序,输出即可

 

  1. #include <iostream>
  2. #include <cmath>
  3. #include <algorithm>
  4. using namespace std;
  5. /*
  6. PROG: fence4
  7. LANG: C++
  8. ID: heben991
  9. */
  10. const int N = 500;
  11. typedef double T;
  12. const T inf = 1e15, eps = 1e-5, pi = acos(-1.0), C = 1e8;
  13. struct point
  14. {
  15.     T x, y;
  16.     point(T a=0, T b=0)
  17.     {
  18.         x=a,y=b;
  19.     }
  20. }p[N], o;
  21. int n;
  22. bool see[N];
  23. T dot(point a, point b, point c)
  24. {
  25.     return (b.x-a.x)*(c.x-a.x) + (b.y-a.y)*(c.y-a.y);
  26. }
  27. T cross(point a, point b)
  28. {
  29.     return a.x*b.y - a.y*b.x;
  30. }
  31. T cross(point a, point b, point c)
  32. {
  33.     return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
  34. }
  35. int sign(T x)
  36. {
  37.     if( x == 0 ) return 0;
  38.     if( x > 0 )return 1;
  39.     return -1;
  40. }
  41. bool checkssint(point a, point b, point c, point d)
  42. {
  43.     return max(a.x,b.x) > min(c.x,d.x)
  44.     && max(a.y,b.y) > min(c.y,d.y)
  45.     && max(c.x,d.x) > min(a.x,b.x)
  46.     && max(c.y,d.y) > min(a.y,b.y)
  47.     && sign(cross(a,b,c))*sign(cross(a,b,d)) < 0
  48.     && sign(cross(c,d,a))*sign(cross(c,d,b)) < 0;
  49. }
  50. bool segsegint(point p1, point p2, point p3, point p4, point &p)
  51. {
  52.     if( !checkssint(p1,p2,p3,p4) ) return 0;
  53.     double d, d1, d2;
  54.     d = (p1.x-p2.x)*(p4.y-p3.y) - (p1.y-p2.y)*(p4.x-p3.x);
  55.     d1 = cross(p3,p4)*(p1.x-p2.x) - cross(p1,p2)*(p3.x-p4.x);
  56.     d2 = cross(p1,p2)*(p4.y-p3.y) - cross(p3,p4)*(p2.y-p1.y);
  57.     p.x = d1/d;
  58.     p.y = d2/d;
  59.     return 1;
  60. }
  61. double dist2(point a, point b)
  62. {
  63.     return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
  64. }
  65. void nearest(T xx, T yy)
  66. {
  67.     point pt(xx,yy), inter;
  68.     double dt, dm = inf;
  69.     int near = -1, i, j, k;
  70.     pt.x += (pt.x-o.x)*C;
  71.     pt.y += (pt.y-o.y)*C;
  72.     for(i = 0; i < n; ++i)
  73.     {
  74.         if(!segsegint(o,pt,p[i],p[i+1],inter))continue;
  75.         dt = dist2(inter, o);
  76.         if(dt < dm)
  77.         {
  78.             dm = dt;
  79.             near = i;
  80.         }
  81.     }
  82.     if(near != -1) see[near] = 1;
  83. }
  84. int main()
  85. {
  86.     int i, j, k;
  87.     freopen("fence4.in""r", stdin);
  88.     freopen("fence4.out","w",stdout);
  89.     scanf("%d%lf%lf", &n, &o.x, &o.y);
  90.     for(i = 0; i < n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y);
  91.     p[n] = p[0];
  92.     p[n+1] = p[1];
  93.     for(i = 0; i < n; ++i)
  94.     {
  95.         if( fabs( cross(p[i],p[i+1],p[i+2]) ) <= eps
  96.             && dot(p[i],p[i+1],p[i+2]) < 0 )
  97.         {
  98.             printf("---%d/n", i);
  99.             break;
  100.         }
  101.         for(j = i+2; j < n; ++j)
  102.         if((j+1)%n != i && checkssint(p[i],p[i+1],p[j],p[j+1]))
  103.         {
  104.             printf("------%d %d/n", i, j);
  105.             break;
  106.         }
  107.         if(j < n)break;
  108.     }
  109.     if(i < n)
  110.     {
  111.         puts("NOFENCE");
  112.         return 0;
  113.     }
  114.     for(i = 0; i < n; ++i)
  115.     {
  116.         nearest(p[i].x-10.0*eps, p[i].y-pi*eps);
  117.         nearest(p[i].x+10.0*eps, p[i].y+10*eps);
  118.     }
  119.     int cnt = 0;
  120.     for(i = 0; i < n; ++i) if(see[i]) ++cnt;
  121.     printf("%d/n", cnt);
  122.     for(i = 0; i < n-2; ++i)
  123.     if(see[i])
  124.     {
  125.         printf("%.0lf %.0lf %.0lf %.0lf/n",p[i].x,p[i].y,p[i+1].x,p[i+1].y);
  126.     }
  127.     if(see[i=n-1])
  128.     {
  129.         printf("%.0lf %.0lf %.0lf %.0lf/n",p[i+1].x,p[i+1].y,p[i].x,p[i].y);
  130.     }
  131.     if(see[i=n-2])
  132.     {
  133.         printf("%.0lf %.0lf %.0lf %.0lf/n",p[i].x,p[i].y,p[i+1].x,p[i+1].y);
  134.     }
  135.     return 0;
  136. }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值