杭电OJ 1154(C++)

#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
using namespace std;

const double eps = 1e-8;
const double INF = 1e20;
const double PI = acos(-1.0);

//判断x是正数、负数、零
int dcmp(double x)
{
    if (fabs(x) < eps) //x是零
        return 0;
    else //x不是零
        return (x < 0 ? -1 : 1);
}

struct Point //点
{
    double x, y;
	Point(double _x = 0, double _y = 0) : x(_x), y(_y) {}
    void input() { cin >> x >> y; }
    bool operator == (const Point& b) const {
        return (dcmp(x - b.x) == 0 && dcmp(y - b.y) == 0);
    }
    bool operator < (const Point& b) const {
        return (dcmp(x - b.x) == 0 ? dcmp(y - b.y) < 0 : x < b.x);
    }
    Point operator + (const Point& b) const {
        return Point(x + b.x, y + b.y);
    }
    Point operator - (const Point& b) const {
        return Point(x - b.x, y - b.y);
    }
    Point operator * (double a) {
        return Point(x * a, y * a);
    }
    Point operator / (double a) {
        return Point(x / a, y / a);
    }
    double len2() { //返回长度的平方
        return pow(x, 2) + pow(y, 2);
    }
    double len() { //返回长度
        return sqrt(len2());
    }
};

double cross(Point a, Point b) //叉积
{
    return a.x * b.y - a.y * b.x;
}
double dot(Point a, Point b) //点积
{
    return a.x * b.x + a.y * b.y;
}
double dis(Point a, Point b) //两个点的距离
{
    Point p = b - a;
    return p.len();
}
double rad_degree(double rad) //弧度转化为角度
{
    return rad / PI * 180;
}
double rad(Point a, Point b) //两个向量的夹角
{
    return fabs(atan2(fabs(cross(a, b)), dot(a, b)));
}
bool parallel(Point a, Point b) //判断两个向量是否平行
{
    double p = rad(a, b);
    return (dcmp(p) == 0 || dcmp(p - PI) == 0);
}

struct Line //线
{
    Point s, e; //直线的两个点
    Line() {}
    Line(Point _s, Point _e) : s(_s), e(_e) {}
    Line(Point p, double ang) //一个点和倾斜角确定直线
    {
        s = p;
        if (dcmp(ang - PI / 2) == 0) {
            e = s + Point(0, 1);
        }
        else
            e = s + Point(1, tan(ang));
    }
    Line(double a, double b, double c) //ax+by+c=0确定直线
    {
        if (dcmp(a) == 0) {
            s = Point(0, -c / b);
            e = Point(1, -c / b);
        }
        else if (dcmp(b) == 0) {
            s = Point(-c / a, 0);
            e = Point(-c / a, 1);
        }
        else {
            s = Point(0, -c / b);
            e = Point(1, (-c - a) / b);
        }
    }
    void input() {
        s.input();
        e.input();
    }
};

int relation(Point p, Line l) //点和直线的关系
{ //1:在左侧 2:在右侧 3:在直线上
    int c = dcmp(cross(p - l.s, l.e - l.s));
    if (c < 0) return 1;
    else if (c > 0) return 2;
    else return 3;
}

bool point_on_seg(Point p, Line l) //判断点是否在线段上
{
    return dcmp(cross(p - l.s, l.e - l.s)) == 0 &&
           dcmp(dot(p - l.s, p - l.e) <= 0);
}

bool parallel(Line a, Line b) //判断两条直线是否平行
{
    return parallel(a.e - a.s, b.e - b.s);
}

int seg_cross_seg(Line a, Line v) //两条线段相交关系
{ //2:规范相交 1:不规范相交 0:不相交
    int d1 = dcmp(cross(a.e - a.s, v.s - a.s));
    int d2 = dcmp(cross(a.e - a.s, v.e - a.s));
    int d3 = dcmp(cross(v.e - v.s, a.s - v.s));
    int d4 = dcmp(cross(v.e - v.s, a.e - v.s));
    if ((d1 ^ d2) == -2 && (d3 ^ d4) == -2)
        return 2;
    return (d1 == 0 && dcmp(dot(v.s - a.s, v.s - a.e)) <= 0) ||
           (d2 == 0 && dcmp(dot(v.e - a.s, v.e - a.e)) <= 0) ||
           (d3 == 0 && dcmp(dot(a.s - v.s, a.s - v.e)) <= 0) ||
           (d4 == 0 && dcmp(dot(a.e - v.s, a.e - v.e)) <= 0);
}

int line_cross_seg(Line a, Line v) //直线和线段相交关系,a为直线,v为线段
{ //2:规范相交 1:非规范相交 0:不相交
    int d1 = dcmp(cross(a.e - a.s, v.s - a.s));
    int d2 = dcmp(cross(a.e - a.s, v.e - a.s));
    if ((d1 ^ d2) == -2) return 2;
    else return (d1 == 0 || d2 == 0);
}

int line_cross_line(Line a, Line v) //两条直线相交关系
{ //0:平行 1:重合 2:相交
    if (parallel(a, v))
        return relation(a.e, v) == 3;
    return 2;
}

Point line_intersection(Line a, Line v) //计算两条直线的交点
{
    double a1 = cross(v.e - v.s, a.s - v.s);
    double a2 = cross(v.e - v.s, a.e - v.s);
    return Point((a.s.x * a2 - a.e.x * a1) / (a2 - a1), (a.s.y * a2 - a.e.y * a1) / (a2 - a1));
}

bool relation(Point q, Point* p, int n) //判断点和多边形的关系
{ //0:外部 1:内部 2:边上 3:顶点
    for (int i = 0; i < n; i++) {
        if (p[i] == q)
            return 3;
    }
    for (int i = 0; i < n; i++) {
        if (point_on_seg(q, Line(p[i], p[(i + 1) % n])))
            return 2;
    }
    int cnt = 0;
    for (int i = 0; i < n; i++) {
        int j = (i + 1) % n;
        int k = dcmp(cross(q - p[j], p[i] - p[j]));
        int u = dcmp(p[i].y - q.y);
        int v = dcmp(p[j].y - q.y);
        if (k > 0 && u < 0 && v >= 0) cnt++;
        if (k < 0 && v < 0 && u >= 0) cnt--;
    }
    return cnt != 0;
}

const int MAXN = 1005;
int n, m;
Point p[MAXN], q[MAXN], ans[MAXN];
Line l[MAXN];
int cnt;

int main()
{
    while (cin >> n >> m)
    {
        if (n == 0 && m == 0)
            break;
        for (int i = 0; i < n; i++) {
            p[i].input();
        }
        while (m--)
        {
            Line l;
            l.input();
            cnt = 0;
            double res = 0;
            for (int i = 0; i < n; i++)
            {
                int j = (i + 1) % n;
                int cur = 0;
                if (relation(p[i], l) == 3) ans[cnt++] = p[i], cur++;
                if (relation(p[j], l) == 3) ans[cnt++] = p[j], cur++;
                if (line_cross_seg(l, Line(p[j], p[i])) == 2) {
                    Point pp = line_intersection(l, Line(p[j], p[i]));
                    ans[cnt++] = pp;
                }
            }
            sort(ans, ans + cnt);
            int cur = 0;
            for (int i = 0; i < cnt; i++)
            {
                if (i && ans[i] == ans[i - 1]) continue;
                else ans[cur++] = ans[i];
            }
            cnt = cur;
            for (int i = 0; i < cnt - 1; i++)
            {
                int j = i + 1;
                if (relation((ans[i] + ans[j]) / 2, p, n))
                    res += dis(ans[i], ans[j]);
            }
            cout << fixed << setprecision(3) << res << endl;
        }
    }
    return 0;
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值