您的位置:首页 > Web前端

usaco 3.4 Closed Fences 计算几何

2008-08-20 16:58 375 查看
题目给定一个多边形,要求
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
, o;

int n;

bool see
;

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
= 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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: