poj2462

来源:互联网 发布:外贸口语书籍推荐,知乎 编辑:程序博客网 时间:2024/06/05 20:27

看八戒在做这个题,我也做了做。。

坑很多,还是要注意细节。不得不吐槽,难道又到了计算几何只能套模板否则就一串WA的情况了么!

要不是八戒做出来了,这题我估计我也就扔到这里了。。哥不服啊~所以得做出来!

注意这个题,重复点、直线等关键词。还有,判断直线跟线段交点,需要先剪枝,就是判断这个线段端点跟直线端点叉乘是不是小于eps就行了。


#include <iostream>
#include <algorithm>
#include <iomanip>
#include <limits>

using namespace std;

#pragma warning(disable:4996)

#define eps 1e-8
#define zero(x) (((x)>0?(x):-(x))<eps)

struct point{ double x, y; };
struct line{ point a, b; };

bool cmp(point p1, point p2)
{
    if (fabs(p1.x - p2.x) < eps) return p1.y < p2.y;
    return p1.x < p2.x;
}

double xmult(point p1, point p2, point p0)
{
    return (p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y);
}

point intersection(line u, line v)
{
    point ret = u.a;
    double t = ((u.a.x - v.a.x)*(v.a.y - v.b.y) - (u.a.y - v.a.y)*(v.a.x - v.b.x)) / ((u.a.x - u.b.x)*(v.a.y - v.b.y) - (u.a.y - u.b.y)*(v.a.x - v.b.x));
    ret.x += (u.b.x - u.a.x)*t;
    ret.y += (u.b.y - u.a.y)*t;
    return ret;
}

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

int inside_polygon(point q, int n, point* p, int offset_x, int offset_y, int on_edge = 2)
{
    point q2;
    int i = 0, count;
    while (i < n)
    for (count = i = 0, q2.x = rand() + offset_x, q2.y = rand() + offset_y; i < n; i++)
    if (zero(xmult(q, p[i], p[(i + 1) % n])) && (p[i].x - q.x)*(p[(i + 1) % n].x - q.x) < eps && (p[i].y - q.y)*(p[(i + 1) % n].y - q.y) < eps)
        return on_edge;
    else if (zero(xmult(q, q2, p[i])))
        break;
    else if (xmult(q, p[i], q2)*xmult(q, p[(i + 1) % n], q2) < -eps&&xmult(p[i], q, p[(i + 1) % n])*xmult(p[i], q2, p[(i + 1) % n]) < -eps)
        count++;
    return count & 1;
}

int main()
{
    int num_of_point, num_of_line;
    while (cin >> num_of_point >> num_of_line && (num_of_point || num_of_line))
    {
        point p[1005];
        memset(p, 0sizeof(p));
        double Max_x = numeric_limits<double>::min(), Max_y = numeric_limits<double>::min();
        for (int i = 0; i < num_of_point; i++)
        {
            cin >> p[i].x >> p[i].y;
            if (p[i].x > Max_x) Max_x = p[i].x;
            if (p[i].y > Max_y) Max_y = p[i].y;
        }
        p[num_of_point] = p[0];//pay attention it has add for one, in reality, the size of it...i've made a mistake here
        for (int i = 0; i < num_of_line; i++)
        {
            line temp;
            cin >> temp.a.x >> temp.a.y >> temp.b.x >> temp.b.y;

            point intersects[1005];
            memset(intersects, 0sizeof(intersects));

            int count_of_intersects = 0;

            for (int i = 0; i < num_of_point; i++)
            {
                if (xmult((p[i]), temp.a, temp.b)*xmult(p[i + 1], temp.a, temp.b) < eps)//can the sigment and the line intersect?
                {
                    if (fabs(xmult((p[i]), temp.a, temp.b)) < eps&&fabs(xmult(p[i + 1], temp.a, temp.b)) < eps)//"same point"
                        continue;
                    line a = { p[i], p[i + 1] };
                    point inter = intersection(a, temp);
                    intersects[count_of_intersects++] = inter;
                }
            }
            sort(intersects, intersects + count_of_intersects, cmp);
            double ans = 0;
            for (int i = 0; i < count_of_intersects - 1; i++)
            {
                point center = { (intersects[i].x + intersects[i + 1].x) / 2, (intersects[i].y + intersects[i + 1].y) / 2 };
                bool flag = inside_polygon(center, num_of_point + 1, p, (int)Max_x + 1, (int)Max_y + 1);
                if (flag == 1 || flag == 2)
                    ans += dist(intersects[i], intersects[i + 1]);
            }
            cout << fixed << setprecision(3) << ans << endl;
        }
    }
    return 0;
}