USACO Section 3.4 Closed Fences(离散化 & 线段规范相交 & 线段非规范相交)

Closed Fences

A closed fence in the plane is a set of non-crossing, connected line segments with N corners (3 < N < 200). The corners or vertices are each distinct and are listed in counter-clockwise order in an array {xi, yi}, i in (1..N).

Every pair of adjacent vertices defines a side of the fence. Thus {xi yi xi+1 yi+1} is a side of the fence for all i in (1..N). For our purposes, N+1 = 1, so that the first and last vertices making the fence closed.

Here is a typical closed fence and a point x,y:

                         * x3,y3
                 x5,y5  / \
    x,y *          *   /   \
                  / \ /     \
                 /   *       \
           x6,y6*   x4,y4     \
                |              \
                |               \
           x1,y1*----------------* x2,y2

Write a program which will do the following:

  • Test an ordered list of vertices {xi,yi}, i in (1..N) to see if the array is a valid fence.
  • Find the set of fence sides that a person (with no height) who is standing in the plane at position (x,y) can "see" when looking at the fence. The location x,y may fall anywhere not on the fence.

A fence side can be seen if there exists a ray that connects (x,y) and any point on the side, and the ray does not intersect any other side of the fence. A side that is parallel to the line of sight is not considered visible. In the figure, above the segments x3,y3-x4,y4; x5,y5-x6,y6; and x6-y6-x1,y1 are visible or partially visible from x,y.

PROGRAM NAME: fence4

INPUT FORMAT

Line 1: N, the number of corners in the fence
Line 2: Two space-separated integers, x and y, that are the location of the observer. Both integers will fit into 16 bits.
Line 3-N+2: A pair of space-separated integers denoting the X,Y location of the corner. The pairs are given in counterclockwise order. Both integers are no larger than 1000 in magnitude.

NOTE: I have added anNew test case #12 for this task. Let me know if you think it's wrong. Rob Be sure to include USACO in your mail subject!

SAMPLE INPUT (file fence4.in)

13
5 5
0 0
7 0
5 2
7 5
5 7
3 5
4 9
1 8
2 5
0 9
-2 7
0 3
-3 1 

OUTPUT FORMAT

If the sequence is not a valid fence, the output is a single line containing the word "NOFENCE".

Otherwise, the output is a listing of visible fence segments, one per line, shown as four space-separated integers that represent the two corners. Express the points in the segment by showing first the point that is earlier in the input, then the point that is later. Sort the segments for output by examining the last point and showing first those points that are earlier in the input. Use the same rule on the first of the two points in case of ties.

SAMPLE OUTPUT (file fence4.out)

7
0 0 7 0
5 2 7 5
7 5 5 7
5 7 3 5
-2 7 0 3
0 0 -3 1
0 3 -3 1

题意:输入一个观看点和 n 个点构成一个多边形,这个多边形在内部相交则输出“NOFENCE”,然后从观看点看多边形可以看到的边就输出,看到端点不算看到。对于每条边输出按输入的顺序,如果两条边的后一个端点相同则按前一个端点的输入顺序(这个只需考虑最后一条边)
分析:
第一问:可以判断线段两两相交(n^2)
第二问:离散化一下,对于每条边从一个端点开始每次增加 0.01 的长度得到一个点,然后判断这个点是否可以看到。
模板:线段的规范和非规范相交

View Code
/*
  ID: dizzy_l1
  LANG: C++
  TASK: fence4
*/
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define MAXN 201
#define EXP 1e-9
#define MIN 0.01

using namespace std;

struct point
{
    double x,y;
} p[MAXN],eye;

//规范相交返回1,非规范相交返回2,不相交返回0;
int dblcmp(double d)
{
    if(fabs(d)<EXP) return 0;
    return (d>0)?1:-1;
}


double cross1(point a,point b,point c)//叉积
{
    double x1,y1,x2,y2;
    x1=c.x-a.x;y1=c.y-a.y;
    x2=b.x-a.x;y2=b.y-a.y;
    return x1*y2-x2*y1;
}

double cross2(point a,point b,point c)//点积
{
    double x1,y1,x2,y2;
    x1=c.x-a.x;y1=c.y-a.y;
    x2=c.x-b.x;y2=c.y-b.y;
    return x1*x2+y1*y2;
}

int segcross(point a,point b,point c,point d)//线段相交
{
    double d1,d2,d3,d4;
    d1=dblcmp(cross1(a,b,c));
    d2=dblcmp(cross1(a,b,d));
    d3=dblcmp(cross1(c,d,a));
    d4=dblcmp(cross1(c,d,b));
    if(d1*d2<0&&d3*d4<0) return 1;  //规格相交
    if(d1==0&&dblcmp(cross2(a,b,c))<=0) return 2; //非规范相交
    if(d2==0&&dblcmp(cross2(a,b,d))<=0) return 2;
    if(d3==0&&dblcmp(cross2(c,d,a))<=0) return 2;
    if(d4==0&&dblcmp(cross2(c,d,b))<=0) return 2;
    return 0;
}

int judge1(int n)//第一问
{
    int i,j,flag;
    for(i=0; i<n; i++)
    {
        for(j=0; j<n; j++)
        {
            if(j==i||j==(i+1)%n||(j+1)%n==i||(j+1)%n==(i+1)%n) continue;
            flag=segcross(p[i],p[(i+1)%n],p[j],p[(j+1)%n]);
            if(flag) return flag;
        }
    }
    return flag;
}

int cnt,n;
bool use[MAXN];
struct ANS
{
    int x1,y1,x2,y2;
} ans[MAXN];

int judge2(point t)//第二问
{
    int i,flag;
    for(i=0; i<n; i++)
    {
        if(use[i]&&use[(i+1)%n]) continue;
        flag=segcross(eye,t,p[i],p[(i+1)%n]);
        if(flag) return flag;
    }
    return flag;
}

bool search(point a,point b)
{
    double k;
    point ta,tb;
    ta=a;tb=b;
    if(a.x>b.x) swap(ta,tb);
    if(fabs(b.x-a.x)<EXP)
    {
        if(ta.y>ta.x) swap(ta,tb);
        while(tb.y-ta.y>EXP)
        {
            ta.y+=0.01;
            if(judge2(ta)==0) return true;
        }
    }
    else
    {
        k=(b.y-a.y)/(b.x-a.x);
        while(tb.x-ta.x>EXP)
        {
            ta.x+=0.01;
            ta.y=k*(ta.x-tb.x)+tb.y;
            if(judge2(ta)==0) return true;
        }
    }

    return false;
}

void work(int n)
{
    int i;
    cnt=0;
    memset(use,false,sizeof(use));
    for(i=0; i<n; i++)
    {
        use[i]=true;
        use[(i+1)%n]=true;
        if(search(p[i],p[(i+1)%n]))
        {
            ans[cnt].x1=p[i].x;
            ans[cnt].y1=p[i].y;
            ans[cnt].x2=p[(i+1)%n].x;
            ans[cnt].y2=p[(i+1)%n].y;
            if(i==n-1)
            {
                swap(ans[cnt].x1,ans[cnt].x2);
                swap(ans[cnt].y1,ans[cnt].y2);
                if(ans[cnt].x2==ans[cnt-1].x2&&ans[cnt].y2==ans[cnt-1].y2)
                    swap(ans[cnt-1],ans[cnt]);
            }
            cnt++;
        }
        use[i]=false;
        use[(i+1)%n]=false;
    }
}

int main()
{
    freopen("fence4.in","r",stdin);
    freopen("fence4.out","w",stdout);
    int i;
    while(scanf("%d",&n)==1)
    {
        scanf("%lf %lf",&eye.x,&eye.y);
        for(i=0; i<n; i++)
            scanf("%lf %lf",&p[i].x,&p[i].y);
        if(judge1(n))
        {
            printf("NOFENCE\n");
            continue;
        }
        work(n);
        printf("%d\n",cnt);
        for(i=0; i<cnt; i++)
        {
            printf("%d %d %d %d\n",ans[i].x1,ans[i].y1,ans[i].x2,ans[i].y2);
        }
    }
    return 0;
}

 

posted @ 2012-09-21 09:43  mtry  阅读(675)  评论(0编辑  收藏  举报