bzoj1091: [SCOI2003]切割多边形

暴力+几何

注意一个很坑的地方,直线可能会经过矩形顶点

#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
#define EPS (1e-6)
#define MAXP 10
int dcmp(double a, double b = 0)
{
    if (fabs(a - b) <= EPS)
        return 0;
    return a < b ? -1 : 1;
}
int n, m, p;
struct Point
{
    double x, y;
    Point(double _x = 0, double _y = 0)
        : x(_x), y(_y) {}
} a[MAXP], center;
typedef Point Vector;
Vector operator- (const Vector &a, const Vector &b)
{
    return Vector(a.x - b.x, a.y - b.y);
}
Vector operator+ (const Vector &a, const Vector &b)
{
    return Vector(a.x + b.x, a.y + b.y);
}
bool operator== (const Point &a, const Point &b)
{
    return dcmp(a.x, b.x) == 0 && dcmp(a.y, b.y) == 0;
}
bool cmp(const Point &a0, const Point &b0)
{
    Point a = a0 - center, b = b0 - center;
    return dcmp(atan2(a.y, a.x), atan2(b.y, b.x)) < 0;
}
double cross(const Vector &a, const Vector &b)
{
    return a.x * b.y - a.y * b.x;
}
double dot(const Vector &a, const Vector &b)
{
    return a.x * b.x + a.y * b.y;
}
bool parallel(const Vector &a, const Vector &b)
{
    return dcmp(a.x * b.y, a.y * b.x) == 0;
}
double length(const Vector &a)
{
    return sqrt(a.x * a.x + a.y * a.y);
}
struct Line
{
    Point p;
    Vector v;
    Line() {}
    Line(Point _p, Vector _v)
        : p(_p), v(_v) {}
} l[MAXP];
Point intersect(const Line &a, const Line &b)
{
    double y = (a.v.x * a.p.y * b.v.y - a.p.x * b.v.y * a.v.y + b.p.x * b.v.y * a.v.y - b.p.y * b.v.x * a.v.y) / (a.v.x * b.v.y - b.v.x * a.v.y);
    double x;
    if (dcmp(a.v.y))
        x = a.v.x / a.v.y * (y - a.p.y) + a.p.x;
    else
        x = b.v.x / b.v.y * (y - b.p.y) + b.p.x;
    return Point(x, y);
}
bool inhalf(const Point &p, const Line &l)
{
    return dcmp(cross(l.v, p - l.p)) >= 0;
}
bool inrec(const Point &a)
{
    return dcmp(a.x) >= 0 && dcmp(a.y) >= 0 && dcmp(a.x, n) <= 0 && dcmp(a.y, m) <= 0;
}
Line inrec(const Line &l)
{
    if (dcmp(l.v.x) == 0)
        return Line(Point(l.p.x, 0), Vector(0, m));
    if (dcmp(l.v.y) == 0)
        return Line(Point(0, l.p.y), Vector(n, 0));
    Point p1, p2, p3, p4;
    p1 = intersect(l, Line(Point(0, 0), Vector(n, 0)));
    p2 = intersect(l, Line(Point(0, 0), Vector(0, m)));
    p3 = intersect(l, Line(Point(0, m), Vector(n, 0)));
    p4 = intersect(l, Line(Point(n, 0), Vector(0, m)));
    bool hv = false;
    Point pp;
    if (inrec(p1))
    {
        hv = true;
        pp = p1;
    }
    if (inrec(p2))
    {
        if (hv && !(pp == p2))
            return Line(pp, p2 - pp);
        hv = true;
        pp = p2;
    }
    if (inrec(p3))
    {
        if (hv && !(pp == p3))
            return Line(pp, p3 - pp);
        hv = true;
        pp = p3;
    }
    return Line(pp, p4 - pp);
}
bool v[MAXP] = {0};
double ans = 1e300;
void dfs(int num, double hv)
{
    if (dcmp(hv, ans) >= 0)
        return;
    if (num == p)
    {
        ans = hv;
        return;
    }
    for (int i = 0; i < p; ++i)
        if (!v[i])
        {
            Line x = inrec(l[i]);
            for (int j = 0; j < p; ++j)
                if (v[j] && !parallel(l[j].v, x.v))
                {
                    Point p = intersect(x, l[j]);
                    if (dcmp(dot(x.p - p, x.p + x.v - p)) < 0)
                    {
                        if (!inhalf(x.p, l[j]))
                            x = Line(p, x.p + x.v - p);
                        else if (!inhalf(x.p + x.v, l[j]))
                            x = Line(x.p, p - x.p);
                    }
                }
            v[i] = 1;
            dfs(num + 1, hv + length(x.v));
            v[i] = 0;
        }
}
int main()
{
    scanf("%d%d%d", &n, &m, &p);
    for (int i = 0; i < p; ++i)
    {
        scanf("%lf%lf", &a[i].x, &a[i].y);
        center = center + a[i];
    }
    center.x /= p, center.y /= p;
    sort(a, a + p, cmp);
    for (int i = 0; i < p - 1; ++i)
        l[i] = Line(a[i], a[i + 1] - a[i]);
    l[p - 1] = Line(a[p - 1], a[0] - a[p - 1]);
    dfs(0, 0);
    printf("%.3lf\n", ans);
    return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值