[计算几何]2018多校 B Pizza Hub

https://codeforces.com/gym/102192/problem/B

给一个三角形三个点的坐标,一条宽为w,长度无限的纸带,问把三角形放在纸带上且边界不越界(可以重合)时最小的长,三角形可以旋转。(就是希望希望分配给这个三角形、恰好包含这个三角形的最小的纸带长度。

解释起来好别扭呀。

分析:因为我着急回去看声入人心以及打游戏,所以字写得有点草率,如果有看的人就凑合看吧咳咳

每种情况中各种杂七杂八的情况判断一下就好了,代码也不复杂。(私以为这个代码超方便的!咳咳不过我没有看过其他人的代码……

关于函数solve和solve1里涉及的角度,画了个图解释一下,x1是L1和上面这条横线交点的横坐标

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
typedef pair<int,int> piir;
const int N = 205;
const db eps=1e-6;
const db pi=acos(-1);
int sign(db k){if(k>eps) return 1;if(k<-eps) return -1;return 0;}
int dcmp(db k1,db k2){return sign(k1-k2);}
struct Point{
    db x,y;
    Point operator - (const Point k)const{return (Point){x-k.x,y-k.y};}
    db abs2(){return x*x+y*y;}
    db abs(){return sqrt(x*x+y*y);}
    db dis(const Point k)const{return ((*this)-k).abs();}
    db dis2(const Point k)const{return ((*this)-k).abs2();}
    void input(){double xx,yy;scanf("%lf%lf",&xx,&yy);x=xx;y=yy;}
}A,B,C;
db cc(Point a,Point b,Point c){
    db ab=a.dis(b),ac=a.dis(c),bc=b.dis(c);
    db ab2=a.dis2(b),ac2=a.dis2(c),bc2=b.dis2(c);
    return (ab2+ac2-bc2)/2/ab/ac;
}
db w;
db solve1(db l1,db l2,db arc){//l1>w的情况,和纸带边缘一定有交点
    db x1=sqrt(l1*l1-w*w);//和纸带边缘的交点
    db turn=acos(w/l1);
    if(dcmp(turn+arc,pi/2)>0) return 1e18;
    db now=pi/2-turn-arc;
    db y=sin(now)*l2;
    if(dcmp(y,w)>0) return sqrt(l2*l2-w*w);
    if(dcmp(x1,cos(now)*l2)<0) x1=cos(now)*l2;
    return x1;
}
db solve(db l1,db l2,db arc){
    if(dcmp(arc,pi/2)>0) return 1e18;//arc大于90°,这个角顶在原点的话啥姿势都塞不下哇
    if(dcmp(l1,w)>=0){
        return solve1(l1,l2,arc);
    }else{
        if(dcmp(l2*cos(arc),w)>0) return sqrt(l2*l2-w*w);
        else{
            return sin(arc)*l2;
        }
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        A.input();B.input();C.input();
        double ww;
        scanf("%lf",&ww);w=ww;
        db arcA=acos(cc(A,B,C));
        db arcB=acos(cc(B,A,C));
        db arcC=acos(cc(C,A,B));
        db ans=1e18;
        db tmp;
        tmp=solve(A.dis(B),A.dis(C),arcA);
        if(dcmp(ans,tmp)>=0) ans=tmp;
      //  cout<<tmp<<endl;
        tmp=solve(A.dis(C),A.dis(B),arcA);
        if(dcmp(ans,tmp)>=0) ans=tmp;
       // cout<<tmp<<endl;

        tmp=solve(B.dis(A),B.dis(C),arcB);
        if(dcmp(ans,tmp)>=0) ans=tmp;
       // cout<<tmp<<endl;
        tmp=solve(B.dis(C),B.dis(A),arcB);
        if(dcmp(ans,tmp)>=0) ans=tmp;
       // cout<<tmp<<endl;

        tmp=solve(C.dis(A),C.dis(B),arcC);
        if(dcmp(ans,tmp)>=0) ans=tmp;
       // cout<<tmp<<endl;
        tmp=solve(C.dis(B),C.dis(A),arcC);
        if(dcmp(ans,tmp)>=0) ans=tmp;
       // cout<<tmp<<endl;
        cout.setf(ios::showpoint);
        cout.precision(10);
        if(ans>1e17) printf("impossible\n");
        else cout<<ans<<endl;
    }
}
/*
5
0 0 4 3 8 0
5
*/

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值