[USACO 6.5.2]Closed Fences

题目大意

  求从一点出发的可视线段.

题解

  先找出没有"被覆盖的点",然后从视点出发和每个可视点连线形成一条矢量线段,然后和每条线段的是否有有交点.

  然后也有很多特殊情况需要处理..这里不再赘述.详情请见代码

代码

/*
TASK:fence4
LANG:C++
*/
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

struct Vector
{
    double x, y;
    
    Vector(double x=0, double y=0) : x(x), y(y)
    {
    }
    
    Vector operator + (Vector rbs)
    {
        return Vector(x + rbs.x, y + rbs.y);
    }
    
    Vector operator - (Vector rbs)
    {
        return Vector(x - rbs.x, y - rbs.y);
    }
    
    Vector operator * (double vari)
    {
        return Vector(x * vari, y * vari);
    }
    
}v[205], per;

const double eps = 1e-10;
int dcmp(double x)
{
    if (fabs(x) < eps) return 0;
    else return x < 0 ? -1 : 1;
}

double cross(Vector A, Vector B)
{
    return A.x * B.y - A.y * B.x;
}

bool judge(Vector a1, Vector a2, Vector b1, Vector b2)
{
    double c1 = cross(a2 - a1, b1 - a1), c2 = cross(a2 - a1, b2 - a1);
    double c3 = cross(b2 - b1, a1 - b1), c4 = cross(b2 - b1, a2 - b1);
    return dcmp(c1) * dcmp(c2) < 0 && dcmp(c3) * dcmp(c4) < 0;
}

bool judge2(Vector a1, Vector a2, Vector b1, Vector b2)
{
    double c1 = cross(a2 - a1, b1 - a1), c2 = cross(a2 - a1, b2 - a1);
    return dcmp(c1) * dcmp(c2) < 0;
}

Vector getv(Vector P, Vector v, Vector Q, Vector w)
{
    Vector u = P - Q;
    double t = cross(w, u) / cross(v, w);
    return P + (v * t);
}

double sqr(double x)
{
    return x * x;
}

double dist(Vector a, Vector b)
{
    return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
}

int n, ansn, ans[205][2];
double mindis[205];
bool coverv[205];

int main()
{
    freopen("fence4.in", "r", stdin);
    freopen("fence4.out", "w", stdout);
    scanf("%d", &n);
    scanf("%lf%lf", &per.x, &per.y);
    for (int i = 0; i < n; ++i) scanf("%lf%lf", &v[i].x, &v[i].y);
    bool flag = true;
    for (int i = 0; i < n; ++i)
    {
        for (int j = i + 2; j < n; ++j)
            if (judge(v[i], v[(i+1) % n], v[j], v[(j+1) % n]))
            {
                flag = false;
                break;
            }
        if (!flag) break;
    }
    if (!flag) printf("NOFENCE\n");
    else
    {
        for (int i = 0; i < n; ++i) mindis[i] = 1e20;
        memset(coverv, false, sizeof(coverv));
        for (int i = 0; i < n; ++i)
        {
            for (int j = 0; j < n; ++j)
            {
                if (j != i && j+1 != i)
                {
                    if (judge2(per, v[i], v[j], v[(j+1) % n]))
                    {
                        Vector tmpv = getv(per, per-v[i], v[j], v[j]-v[(j+1) % n]);
                        if (dcmp(tmpv.x-per.x) * dcmp(v[i].x-per.x) < 0 || dcmp(tmpv.y-per.y) * dcmp(v[i].y-per.y) < 0) continue;
                        mindis[i] = min(mindis[i], dist(per, tmpv));
                    }
                }
                if (i != j && cross(v[i]-per, v[j]-per) == 0)
                {
                    if (dcmp(v[j].x-per.x) * dcmp(v[i].x-per.x) < 0 || dcmp(v[j].y-per.y) * dcmp(v[i].y-per.y) < 0) continue;
                    if (dist(v[i], per) < dist(v[j], per)) coverv[j] = true;
                    else coverv[i] = true;
                }
            }
        }
        ansn = 0;
        for (int i = 0; i < n; ++i)
        {
            if (cross(v[i] - per, v[(i+1) % n] - per) == 0) continue;
            double d1 = dist(per, v[i]), d2 = dist(per, v[(i+1) % n]);
            int j = i;
            bool canbeseen = true;
            if (d1 > mindis[j] || coverv[j])
            {
                for (;;)
                {
                    if (j == -1) j = n - 1;
                    if (j == (i+1) % n)
                    {
                        canbeseen = false;
                        break;
                    }
                    if (!coverv[j])
                    {
                        int left = (j-1+n)%n, right = (j+1)%n;
                        if (dcmp(cross(v[j]-per, v[left]-per)) * dcmp(cross(v[j]-per, v[right]-per)) > 0)
                            if (judge2(per, v[j], v[i], v[(i+1) % n]))
                            {
                                Vector tmpv = getv(per, per-v[j], v[i], v[i]-v[(i+1) % n]);
                                if (abs(mindis[j] - dist(per, tmpv)) < eps) break;
                            }
                    }
                    j--;
                }
            }
            int tmp = j;
            j = (i+1) % n;
            if (d2 > mindis[j] || coverv[j])
            {
                for (;;)
                {
                    if (j == n) j = 0;
                    if (j == i)
                    {
                        canbeseen = false;
                        break;
                    }
                    if (!coverv[j])
                    {
                        int left = (j-1+n)%n, right = (j+1)%n;
                        if (dcmp(cross(v[j]-per, v[left]-per)) * dcmp(cross(v[j]-per, v[right]-per)) > 0)
                            if (judge2(per, v[j], v[i], v[(i+1) % n]))
                            {
                                Vector tmpv = getv(per, per-v[j], v[i], v[i]-v[(i+1) % n]);
                                if (abs(mindis[j] - dist(per, tmpv)) < eps) break;
                            }
                    }
                    j++;
                }
            }
            if (canbeseen && (cross(v[tmp] - per, v[j] - per) != 0))
            {
                ans[ansn][0] = i;
                ans[ansn][1] = (i+1) % n;
                if (ans[ansn][1] < ans[ansn][0]) swap(ans[ansn][0], ans[ansn][1]);
                j = ansn;
                ansn++;
                while (j != 0 && ans[j][1] == ans[j-1][1] && ans[j][0] < ans[j-1][0])
                {
                    swap(ans[j][0], ans[j-1][0]);
                    swap(ans[j][1], ans[j-1][1]);
                    j--;
                }
            }
        }
        printf("%d\n", ansn);
        for (int i = 0; i < ansn; ++i)
            printf("%.0lf %.0lf %.0lf %.0lf\n", v[ans[i][0]].x, v[ans[i][0]].y, v[ans[i][1]].x, v[ans[i][1]].y);
    }
    return 0;
}

 

posted @ 2017-01-23 12:03  albertxwz  阅读(216)  评论(0编辑  收藏  举报