题目给定一个多边形,要求
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)输出要求先按第二点排序,再第一点,实际上,只需要把最后一条线段的两点交换顺序,再把最后两条线段交换顺序,输出即可
- #include <iostream>
- #include <cmath>
- #include <algorithm>
- using namespace std;
- /*
- PROG: fence4
- LANG: C++
- ID: heben991
- */
- const int N = 500;
- typedef double T;
- const T inf = 1e15, eps = 1e-5, pi = acos(-1.0), C = 1e8;
- struct point
- {
- T x, y;
- point(T a=0, T b=0)
- {
- x=a,y=b;
- }
- }p[N], o;
- int n;
- bool see[N];
- T dot(point a, point b, point c)
- {
- return (b.x-a.x)*(c.x-a.x) + (b.y-a.y)*(c.y-a.y);
- }
- T cross(point a, point b)
- {
- return a.x*b.y - a.y*b.x;
- }
- T cross(point a, point b, point c)
- {
- return (b.x-a.x)*(c.y-a.y) - (c.x-a.x)*(b.y-a.y);
- }
- int sign(T x)
- {
- if( x == 0 ) return 0;
- if( x > 0 )return 1;
- return -1;
- }
- bool checkssint(point a, point b, point c, point d)
- {
- return max(a.x,b.x) > min(c.x,d.x)
- && max(a.y,b.y) > min(c.y,d.y)
- && max(c.x,d.x) > min(a.x,b.x)
- && max(c.y,d.y) > min(a.y,b.y)
- && sign(cross(a,b,c))*sign(cross(a,b,d)) < 0
- && sign(cross(c,d,a))*sign(cross(c,d,b)) < 0;
- }
- bool segsegint(point p1, point p2, point p3, point p4, point &p)
- {
- if( !checkssint(p1,p2,p3,p4) ) return 0;
- double d, d1, d2;
- d = (p1.x-p2.x)*(p4.y-p3.y) - (p1.y-p2.y)*(p4.x-p3.x);
- d1 = cross(p3,p4)*(p1.x-p2.x) - cross(p1,p2)*(p3.x-p4.x);
- d2 = cross(p1,p2)*(p4.y-p3.y) - cross(p3,p4)*(p2.y-p1.y);
- p.x = d1/d;
- p.y = d2/d;
- return 1;
- }
- double dist2(point a, point b)
- {
- return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
- }
- void nearest(T xx, T yy)
- {
- point pt(xx,yy), inter;
- double dt, dm = inf;
- int near = -1, i, j, k;
- pt.x += (pt.x-o.x)*C;
- pt.y += (pt.y-o.y)*C;
- for(i = 0; i < n; ++i)
- {
- if(!segsegint(o,pt,p[i],p[i+1],inter))continue;
- dt = dist2(inter, o);
- if(dt < dm)
- {
- dm = dt;
- near = i;
- }
- }
- if(near != -1) see[near] = 1;
- }
- int main()
- {
- int i, j, k;
- freopen("fence4.in", "r", stdin);
- freopen("fence4.out","w",stdout);
- scanf("%d%lf%lf", &n, &o.x, &o.y);
- for(i = 0; i < n; ++i) scanf("%lf%lf", &p[i].x, &p[i].y);
- p[n] = p[0];
- p[n+1] = p[1];
- for(i = 0; i < n; ++i)
- {
- if( fabs( cross(p[i],p[i+1],p[i+2]) ) <= eps
- && dot(p[i],p[i+1],p[i+2]) < 0 )
- {
- printf("---%d/n", i);
- break;
- }
- for(j = i+2; j < n; ++j)
- if((j+1)%n != i && checkssint(p[i],p[i+1],p[j],p[j+1]))
- {
- printf("------%d %d/n", i, j);
- break;
- }
- if(j < n)break;
- }
- if(i < n)
- {
- puts("NOFENCE");
- return 0;
- }
- for(i = 0; i < n; ++i)
- {
- nearest(p[i].x-10.0*eps, p[i].y-pi*eps);
- nearest(p[i].x+10.0*eps, p[i].y+10*eps);
- }
- int cnt = 0;
- for(i = 0; i < n; ++i) if(see[i]) ++cnt;
- printf("%d/n", cnt);
- for(i = 0; i < n-2; ++i)
- if(see[i])
- {
- printf("%.0lf %.0lf %.0lf %.0lf/n",p[i].x,p[i].y,p[i+1].x,p[i+1].y);
- }
- if(see[i=n-1])
- {
- printf("%.0lf %.0lf %.0lf %.0lf/n",p[i+1].x,p[i+1].y,p[i].x,p[i].y);
- }
- if(see[i=n-2])
- {
- printf("%.0lf %.0lf %.0lf %.0lf/n",p[i].x,p[i].y,p[i+1].x,p[i+1].y);
- }
- return 0;
- }