CSU 1533 Laser Cutting

区分这四种不同的情况:


第一个是合法的,第二个是非简单多边形,第三个是多重嵌套,第四个是相交。

点在多边形内和简单多边形的判定,是很基础的东西呢。

之前想用数据结构,但是没什么想法。


#include <algorithm>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <stdio.h>
#include <math.h>
using namespace std;
#define MAXN 60
#define eps 1e-18
#define INF 1000100

//const double pi = acos(-1.0);
inline double sig(double x) { return (x > eps) - (x < -eps); };
template <class T> inline T sqr(T a) { return a * a; }

struct Point
{
    double x, y;
    Point() {}
    Point(double _x, double _y): x(_x), y(_y) {}
    void in();
    void out() const;
    double len() const;
    double len2() const;
    double dis(const Point &argu) const;
    double dis2(const Point &argu) const;
    bool operator <(const Point &argu) const;
    Point operator -(const Point &argu) const;
    bool operator ==(const Point &argu) const;
    bool operator !=(const Point &argu) const;
    double operator ^(const Point &argu) const;
    double operator *(const Point &argu) const;
};

struct Segment
{
    Point s, e;
    Segment() {}
    Segment(Point _s, Point _e): s(_s), e(_e) {}
    void in();
    Point d() const;
    void out() const;
    double len() const;
    double len2() const;
    int sgn(const Segment &argu) const;
    bool qrt(const Segment &argu) const;
    double dis(const Point &argu) const;
    double dis2(const Point &argu) const;
    double dis(const Segment &argu) const;
    double dis2(const Segment &argu) const;
    double operator ^(const Segment &argu) const;
};

struct Line
{
    Segment s;
    Line() {}
    Line(Segment _s): s(_s) {}
    Line(Point _s, Point _e): s(Segment(_s, _e)) {}
    double dis(const Line &argu) const;
    double dis2(const Line &argu) const;
    double dis(const Point &argu) const;
    double dis2(const Point &argu) const;
    double dis(const Segment &argu) const;
    double dis2(const Segment &argu) const;
};
inline double Cross(const Point &o, const Point &a, const Point &b) { return (a - o) ^ (b - o); }

void Point::in() { scanf("%lf%lf", &x, &y); }
double Point::len() const { return sqrt(len2()); }
double Point::len2() const { return x * x + y * y; }
void Point::out() const{ printf("%.0lf %.0lf\n", x, y); }
double Point::dis(const Point &argu) const { return sqrt(dis2(argu)); }
bool Point::operator !=(const Point &argu) const { return !((*this) == argu); }
double Point::operator ^(const Point &argu) const { return x * argu.y - y * argu.x; }
double Point::operator *(const Point &argu) const { return x * argu.x + y * argu.y; }
bool Point::operator ==(const Point &argu) const { return x == argu.x && y == argu.y; }
Point Point::operator -(const Point &argu) const { return Point(x - argu.x, y - argu.y); }
bool Point::operator <(const Point &argu) const { return sig(x - argu.x) == 0 ? y < argu.y : x < argu.x; }
double Point::dis2(const Point &argu) const { return (x - argu.x) * (x - argu.x) + (y - argu.y) * (y - argu.y); }

void Segment::in() { s.in(), e.in(); }
Point Segment::d() const { return e - s; }
double Segment::len2() const { return d().len2(); }
double Segment::len() const { return sqrt(len2()); }
void Segment::out() const { s.out(), e.out(); }
double Segment::dis2(const Segment &argu) const
{
    if(~sgn(argu)) return 0;
    return min(min(dis2(argu.s), dis2(argu.e)), min(argu.dis2(s), argu.dis2(e)));
}
double Segment::dis2(const Point &argu) const
{
    Point ps = argu - s, pe = argu - e;
    if(sig(d() * ps) <= 0) return ps.len2();
    if(sig(d() * pe) >= 0) return pe.len2();
    Line l = Line((*this)); return l.dis2(argu);
}
int Segment::sgn(const Segment &argu) const
{
    if(!qrt(argu)) return -1;
    return sig(Cross(s, e, argu.s)) * sig(Cross(s, e, argu.e)) <= 0 &&
           sig(Cross(argu.s, argu.e, s)) * sig(Cross(argu.s, argu.e, e)) <= 0 ? 1 : -1;
}
//快速排斥实验
bool Segment::qrt(const Segment &argu) const
{
    return min(s.x, e.x) <= max(argu.s.x, argu.e.x) && min(s.y, e.y) <= max(argu.s.y, argu.e.y) &&
           min(argu.s.x, argu.e.x) <= max(s.x, e.x) && min(argu.s.y, argu.e.y) <= max(s.y, e.y);
}
double Segment::dis(const Point &argu) const { return sqrt(dis2(argu)); }
double Segment::dis(const Segment &argu) const { return sqrt(dis2(argu)); }

double Line::dis(const Point &argu) const { return sqrt(dis2(argu)); }
double Line::dis2(const Point &argu) const { return sqr(fabs(s.d() ^ (argu - s.s))) / s.len2(); }
double Line::dis(const Segment &argu) const { return sqrt(dis2(argu)); }
double Line::dis2(const Segment &argu) const
{
    Point v1 = argu.s - s.s, v2 = argu.e - s.e; double d1 = s.d() ^ v1, d2 = s.d() ^ v2;
    return sig(d1) != sig(d2) ? 0 : sqr(min(fabs(d1), fabs(d2))) / s.len2();
}

bool issimple(int n, Point p[])
{
    int cn;
    Segment l1, l2;
    for(int j, i = 0; i < n; i++)
    {
        l1 = Segment(p[i], p[i + 1]);
        cn = n - 3, j = i;
        while(cn)
        {
            l2 = Segment(p[(j + 2) % n], p[(j + 3) % n]);
            if(~l1.sgn(l2)) break;
            cn--, j++;
        }
        if(cn) return false;

    }
    return true;
}

bool intersect(const Segment &ss, int n, Point p[])
{
    for(int i = 0; i < n; i++)
    {
        Segment s = Segment(p[i], p[i + 1]);
        if(~ss.sgn(s)) return true;
    }
    return false;
}

int cal_pos(const Segment &ss, int n, Point p[])
{
    int ret = 0;
    for(int i = 0; i < n; i++)
    {
        Segment s = Segment(p[i], p[i + 1]);
        if(sig(s.dis2(ss)) == 0)
        {
            ret++;
            if((s.d() ^ ss.d()) == 0) ret++;
        }
    }
    return ret;
}

void simplify(int &n, Point p[])
{
    int cnt = 1;
    for(int i = 2; i <= n; i++)
    {
        Segment s1 = Segment(p[cnt - 1], p[cnt]);
        Segment s2 = Segment(p[cnt], p[i]);
        if(cnt > 0 && sig(s1.d() ^ s2.d()) == 0) cnt--;
        p[++cnt] = p[i];
    }
    n = cnt + 1;
    p[n] = p[0];
}

Point pp[MAXN][MAXN];
int n[MAXN];
//INVALID POLYGON
//INTERSECTING POLYGONS
//INVALID NESTING
bool c1, c2, c3;
bool in[MAXN];

int main()
{
//    freopen("I.in", "r", stdin);

    int cas; scanf("%d", &cas);
    while(cas--)
    {
        c1 = c2 = c3 = false;

        int p; scanf("%d", &p);
        for(int k = 0; k < p; k++)
        {
            scanf("%d", &n[k]); n[k]--;
            for(int i = 0; i <= n[k]; i++) pp[k][i].in();
            if(c1) continue;
            if(pp[k][0] != pp[k][n[k]]) c1 = true;
            if(!issimple(n[k], pp[k])) c1 = true;
        }
        if(c1) { puts("INVALID POLYGON"); continue; }

        for(int k = 0; k < p; k++) simplify(n[k], pp[k]);

//        for(int k = 0; k < p; k++)
//        {
//            for(int i = 0; i < n[k]; i++) pp[k][i].out();
//            cout << endl;
//        }

        for(int k = 0; !c2 && k < p; k++)
        {
            for(int i = 0; !c2 && i < n[k]; i++)
            {
                Segment s = Segment(pp[k][i], pp[k][i + 1]);
                for(int j = k + 1; !c2 && j < p; j++) if(intersect(s, n[j], pp[j])) c2 = true;
            }
        }
        if(c2) { puts("INTERSECTING POLYGONS"); continue; }

        memset(in, false, sizeof(in));
        for(int k = 0; !c3 && k < p; k++)
        {
            for(int j = 0; !c3 && j < p; j++)
            {
                if(k == j) continue;
                bool flag = true;
                for(int i = 0; flag && i < n[k]; i++)
                {
                    //判断pp[k][i]是否在多边形j内
                    Point _p = Point(INF, pp[k][i].y);
                    Segment s = Segment(pp[k][i], _p);
                    if(cal_pos(s, n[j], pp[j]) % 2 == 0) flag = false;
                }
                if(flag)
                {
                    if(in[k]) c3 = true;
                    in[k] = true;
                }
            }
        }

        if(c3) { puts("INVALID NESTING"); continue; }

        puts("CORRECT");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值