2018HDU 多校8 1002 Pizza Hub

题意:一个宽度固定的纸带,选一个最小的高使其能装下一个给定的三角形

大致思路:枚举三角形一条边在矩形上下边的情况和边靠边的情况。计算几何没什么特别的难点,关键是要耐心,细心。

//#pragma comment(linker, "/stack:200000000")
//#pragma GCC optimize("Ofast,no-stack-protector")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
using namespace std;

double eps = 1e-9;
int sign(double x) {
    if (fabs(x) < eps) return 0;
    return x > 0 ? 1 : -1;
}
double sqr(double x) {
    return x * x;
}
struct point {
    double x, y;
    void read() {
        scanf("%lf%lf", &x, &y);
    }
    void out() {
        printf("x = %f y = %f\n", x, y);
    }
    point(double x = 0, double y = 0) :x(x), y(y) {}
    point operator + (const point &rhs) const {
        return point(x + rhs.x, y + rhs.y);
    }
    point operator - (const point &rhs) const {
        return point(x - rhs.x, y - rhs.y);
    }
    point operator * (const double &k) const {
        return point(x * k, y * k);
    }
    point operator / (const double &k) const {
        return point(x / k, y / k);
    }
    point normal() {
        double l = sqrt(sqr(x) + sqr(y));
        return point(-y / l, x / l);
    }
    bool operator < (const point &rhs) const {
        if (sign(x - rhs.x) == 0) return y < rhs.y;
        return x < rhs.x;
    }
}p[3];
struct seg {
    double len, ang;
}s[3];
double dis(point a, point b) {
    return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
}
double cosine(double a, double b, double c) {
    return (a * a + b * b - c * c) / (2 * a * b);
}
const double pi = acos(-1);

double w;
int t;
int main() {
    scanf("%d", &t);
    while (t--) {
        for (int i = 0; i < 3; i++) p[i].read();
        sort(p, p + 3);
        scanf("%lf", &w);
        for (int i = 0; i < 3; i++) s[i].len = dis(p[i], p[(i + 1) % 3]);
        for (int i = 0; i < 3; i++) s[i].ang = acos(cosine(s[(i + 1) % 3].len, s[(i - 1) < 0 ? 2 : i - 1].len, s[i].len));
        double hf = (s[0].len + s[1].len + s[2].len) / 2;
        double area = sqrt(hf * (hf - s[0].len) * (hf - s[1].len) * (hf - s[2].len));
        if (s[0].len <= w + eps && s[1].len <= w + eps && s[2].len <= w + eps) {
            printf("%.9f\n", 2 * area / max({s[0].len, s[1].len, s[2].len}));
            continue;
        }
        double ans = 1e18;
        for (int i = 0; i < 3; i++) {
            if (s[i].len < w) continue;
            point e = point(sqrt(sqr(s[i].len) - sqr(w)), w);
            point f1, f2, f3, f4;
            point unit = (e / dis(point(), e)) * cos(s[(i - 1) < 0 ? 2 : i - 1].ang) * s[(i + 1) % 3].len;
            point vec = e.normal() * (2 * area / s[i].len);
            f1 = unit + vec;
            f2 = e - unit + vec;
            f3 = unit - vec;
            f4 = e - unit - vec;

            if (f1.y >= -eps && f1.y <= w + eps) ans = min(ans, max({fabs(f1.x - e.x), fabs(f1.x), e.x}));
            if (f2.y >= -eps && f2.y <= w + eps) ans = min(ans, max({fabs(f2.x - e.x), fabs(f2.x), e.x}));
            if (f3.y >= -eps && f3.y <= w + eps) ans = min(ans, max({fabs(f3.x - e.x), fabs(f3.x), e.x}));
            if (f4.y >= -eps && f4.y <= w + eps) ans = min(ans, max({fabs(f4.x - e.x), fabs(f4.x), e.x}));
        }
        for (int i = 0; i < 3; i++) {
            double h = 2 * area / s[i].len;
            double ww;
            if (s[(i - 1) < 0 ? 2 : i - 1].ang > pi / 2 + eps) {
                ww = s[(i - 1) < 0 ? 2 : i - 1].len * fabs(cos(s[(i + 1) % 3].ang));
            }
            else if (s[(i + 1) % 3].ang > pi / 2 + eps){
                ww = s[(i + 1) % 3].len * fabs(cos(s[(i - 1) < 0 ? 2 : i - 1].ang));
            }
            else ww = s[i].len;
            if (h < w + eps) ans = min(ans, ww);
            if (ww < w + eps) ans = min(ans, h);
        }
        if (ans < 1e17) printf("%.9f\n", ans);
        else puts("impossible");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值