Closed Fences[USACO]

这道题断断续续做了有两三天了,真纠结。

写下分析:

%%第一问好解,用线段相交的判断就好:满足条件1 && 条件2

1.以线段为对角线的长方形要相交

2.两对端点互相跨立

设这四个点为x1,y1,x2,y2,x3,y3,x4,y4

L1的坐标为t1=x1-x2,w1=y1-y2,1端点到3,4的线段向量分别为t2=x1-x3,w2=y1-y3,t3=x1-x4,w3=y1-y4;

则3,4在L1两端即为(t1*w2-t2*w1)*(t1*w3-t3*w1)<=0     (等于0的情况发生在重合的情况下。在满足了第一个条件之后,这里的等号可以去掉了)

%%第二问就没那么容易想了:

当一条边可以被看到时,一定存在一个点Po, Pob--Po 这条线段不与多边形中的其他线段相交,我们从Po向左取点,当向左达到点o'(Po' Pob Pol共线,其中Pol为多边形的一个定点),至此o'点为此可见线段的左端点,同样存在右端点。左右端点做成此可见线段的可见范围,当o'与Pol为一个点时,此范围为闭集,否则为开集。

于是,第二问我们可以这么解答,Pob与Pol连线,向左/右偏转一个角度,得一个射线,求此射线下与此多边形相交的第一条边,此边可见。

那么如何确定这个角度a和如何求第一条相交边呢。

求a:

求所有Pob与Pol相连的向量与x轴的夹角,所有夹角间的非0差值为最小相差角度,此角度*1/2 = a

求相交的第一条边:

求相交所得交点px,Pob--Px距离最短

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

题目如下:

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
 
 
-------------------------程序------------------------

/*
ID: zhangyc1
LANG: C++
TASK: fence4
*/
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <set>
using namespace std;

ofstream fileout("fence4.out");

typedef struct
{
    double x, y;
} Point;

Point arrPoint[200];
Point pointOb;
bool arrSeen[200] = {false};
double dbAppZero = 1e-10;
int arrOrder[200];
const double PI = 3.1415926;

int nCount = 0;
Point arrResPoint[400];
int N;
vector<Point> vtPoint;

inline bool IntersectRect(const Point& p0, const Point& p1, const Point& q0, const Point& q1)
{
    if (min(p0.x, p1.x) < max(q0.x, q1.x) &&
        min(p0.y, p1.y) < max(q0.y, q1.y) &&
        min(q0.x, q1.x) < max(p0.x, p1.x) &&
        min(q0.y, q1.y) < max(p0.y, p1.y) )
    {
        return true;
    }
    return false;
}

bool IntersectLine(const Point& p0, const Point& p1, const Point& q0, const Point& q1)
// 只有在两条线段互相跨立时才相交
{
    double dbQ = ((p0.x - q0.x)*(p1.y - q0.y) - (p0.y - q0.y)*(p1.x - q0.x))*((p0.x - q1.x)*(p1.y - q1.y) - (p0.y - q1.y)*(p1.x - q1.x));
    if (dbQ >= 0)
        return false;

    double dbP = ((q0.x - p0.x)*(q1.y - p0.y) - (q0.y - p0.y)*(q1.x - p0.x))*((q0.x - p1.x)*(q1.y - p1.y) - (q0.y - p1.y)*(q1.x - p1.x));
    if (dbP >= 0)
        return false;
    return true;
}

bool LineBeSeen(Point pOb, double theta, int& nStartPointIndex)
// return a line that intersects which Line(pOb, theta), and letting the crossing point be pCr pOb-pCr should have the minst distance
{
    bool bResult = false;
    double dbMinDist = 32767.0;
    // 1.Check if the startpoint and endpoint is in the different part of the line
    for (int i = 0; i < N; i++)
    {
        Point& p0 = arrPoint[i];
        Point& p1 = arrPoint[(i + 1) % N];
        double dbLen = 2 * sqrt((pOb.x - p0.x) * (pOb.x - p0.x) + (pOb.y - p0.y) * (pOb.y - p0.y));
        double db = (cos(theta)*(p0.y - pOb.y) - (sin(theta))*(p0.x - pOb.x))*(cos(theta)*(p1.y - pOb.y) - (sin(theta))*(p1.x - pOb.x));
        if (db + dbAppZero > 0)
        {
            continue;
        }
        db = ((pOb.x + dbLen *cos(theta) - p0.x)*(p1.y - p0.y) - (pOb.y + dbLen * sin(theta) - p0.y)*(p1.x - p0.x))*
            ((pOb.x - p0.x)*(p1.y - p0.y) - (pOb.y - p0.y)*(p1.x - p0.x));
        if (db + dbAppZero > 0)
        {
            continue;
        }

        bResult = true;
        double curDist = abs((p1.y - p0.y) * pOb.x + (p0.x - p1.x) * pOb.y + p0.y * p1.x  - p0.x * p1.y)/* / sqrt((p1.y - p0.y) *(p1.y - p0.y) + (p0.x - p1.x) *(p0.x - p1.x))*/;
        double dbSin = abs((p1.x - p0.x)*(sin(theta)) - (p1.y - p0.y)*(cos(theta)))/* / sqrt((p1.y - p0.y) *(p1.y - p0.y) + (p0.x - p1.x) *(p0.x - p1.x))*/;
        curDist /= dbSin;
        if (dbMinDist > curDist)
        {
            dbMinDist = curDist;
            nStartPointIndex = i;
        }
    }
//     if (bResult)
//     {
//         cout << "Theta : " << theta << " see " << arrPoint[nStartPointIndex].x << " " << arrPoint[nStartPointIndex].y << endl;
//     }
    return bResult;
}

void GetThetaSet(Point pOb, vector<double>& vtTheta)
{
    vector<double> vtTemp;
    for (int i = 0; i < N; i++)
    {
        double dbTheta = atan2(arrPoint[i].y - pOb.y, arrPoint[i].x - pOb.x);
        vtTemp.push_back(dbTheta);
    }

    double dbMinDif = 10;
    for (int i = 0; i < vtTemp.size(); i++)
    {
        for (int j = i + 1; j < vtTemp.size(); j++)
        {
            double dbTemp = abs(vtTemp[i] - vtTemp[j]);
            if (dbTemp > PI)
            {
                dbTemp = 2 * PI - dbTemp;
            }
            if (dbTemp > dbAppZero && dbTemp < dbMinDif)
            {
                dbMinDif = dbTemp;
            }
        }
    }
    dbMinDif /= 2;

    for (int i = 0; i < vtTemp.size(); i++)
    {
        vtTheta.push_back(vtTemp[i] - dbMinDif);
        vtTheta.push_back(vtTemp[i] + dbMinDif);
    }
}

void prepairData()
{
    ifstream filein("fence4.in");
    filein >> N;
    filein >> pointOb.x >> pointOb.y;
    for (int i = 0; i < N; i++)
    {
        filein >> arrPoint[i].x >> arrPoint[i].y;
    }
    filein.close();
}

void process()
{
    // 1.判断是否有两条线段相交
    for (int i = 0; i < N - 2; i++)
    {
        // 第一条线段为point[i-1] -- point[i]
        for (int j = i + 2; j < N; j++)
        {
            if (i == 0 && j == N-1)
            {
                break;
            }
            if (IntersectRect(arrPoint[i], arrPoint[i + 1], arrPoint[j], arrPoint[(j + 1)% N]) && IntersectLine(arrPoint[i], arrPoint[i + 1], arrPoint[j], arrPoint[(j + 1)% N]))
            {
                fileout << "NOFENCE" << endl;
                return;
            }
        }
    }

    // 2.找出所有点p满足pointOb--p 除共点p的线段外不与任何线段相交
    vector<double> vtTheta;
    set<int> setSeen;
    GetThetaSet(pointOb, vtTheta);
    int nStartPointIndex;
    for (int i = 0; i < vtTheta.size(); i++)
    {
        bool bSeen = LineBeSeen(pointOb, vtTheta[i], nStartPointIndex);
        if (bSeen)
        {
            setSeen.insert(nStartPointIndex);
        }
    }

    fileout << setSeen.size() << endl;

    for (int i = 0; i < N - 2; i++)
    {
        if (setSeen.count(i) == 1)
        {
            fileout << arrPoint[i].x << " " << arrPoint[i].y << " " << arrPoint[i+ 1].x << " " << arrPoint[i + 1].y << endl;
        }
    }
    if (setSeen.count(N - 1) == 1)
    {
        fileout << arrPoint[0].x << " " << arrPoint[0].y << " " << arrPoint[N - 1].x << " " << arrPoint[N - 1].y << endl;
    }
    if (setSeen.count(N - 2) == 1)
    {
        fileout << arrPoint[N - 2].x << " " << arrPoint[N - 2].y << " " << arrPoint[N - 1].x << " " << arrPoint[N - 1].y << endl;
    }
}

int main(){
    prepairData();
    process();
    fileout.close();   
    return 0;
}

posted @ 2013-03-01 12:27  J.Z's World  阅读(452)  评论(0编辑  收藏  举报