AT_joisc2016_k 题解

1|0AT_joisc2018_b

传送门

1|1题意

有一个以原点为中心的正方形,有 n(n100) 条不在正方形内部的线段,你需要画一些不在正方形内部的线段,使得这些线段可以把正方形围起来,要求最小化你画的线段的长度和。

1|2思路

我们需要画出一条闭合折线,并且能够把正方形包围。

考虑我们一定是把已有线段用新的线段连起来,或者是让已有线段和正方形边界连起来。因为线段不能在正方形内,我们把两个线段连接起来如果要用正方形边界,就一定会覆盖一个拐角,就是说一定不会只用正方形一条边界的一部分,因此我们可以把只把正方形的四个角当成线段,这样我们就只需要考虑连接两个线段的贡献了。

对于每一对线段,我们求出连接这两个线段最小的代价和这条线段。注意如果这条线段和正方形有交,我们就不能选这条线段,而且我们用其他方式直接连接这两个线段一定没有通过正方形边界更优,因此不用考虑。现在问题就变成了找最小的环使得包含这个正方形。

对于判包含,我们可以从正方形中引出一条射线,如果这条射线经过了折线奇数次,就说明被包含了正方形。

于是对于每一对线段,我们求出连接这两个点的线段经过了射线多少次,这样我们的问题就是求一个经过射线次数为奇数的最小环,可以用 Floyd 解决。

复杂度 O(n3)

点击查看代码
mt19937 nsc(time(0)); const int N=105; const double eps=1e-8,inf=1e18,pi=acos(-1); int n; double S,SS; inline int cmp(double a,double b){ if(fabs(a-b)<eps)return 0; return a>b?1:-1; } struct point{ double x,y; point() {} point (double xx,double yy){x=xx,y=yy;} point operator +(const point &a)const{return point(x+a.x,y+a.y);} point operator -(const point &a)const{return point(x-a.x,y-a.y);} point operator *(const double &a)const{return point(x*a,y*a);} point operator /(const double &a)const{return point(x/a,y/a);} double operator *(const point &a)const{return x*a.y-y*a.x;} double operator /(const point &a)const{return x*a.x+y*a.y;} double length(){return sqrt(x*x+y*y);} }; struct segment{ point a,b; segment() {} segment(point aa,point bb){a=aa,b=bb;} inline double length(){return (b-a).length();} bool operator <(const segment &x)const{return 0;} }a[N],line; double f[N][N][2]; inline bool checkcap(double l1,double r1,double l2,double r2){ if(r1<l1)swap(l1,r1); if(r2<l2)swap(l2,r2); if(!~cmp(r1,l2))return 0; if(!~cmp(r2,l1))return 0; return 1; } inline bool cross(segment a,segment b){ if(!checkcap(a.a.x,a.b.x,b.a.x,b.b.x))return 0; if(!checkcap(a.a.y,a.b.y,b.a.y,b.b.y))return 0; int flag1=cmp((a.b-a.a)*(b.a-a.a),0),flag2=cmp((a.b-a.a)*(b.b-a.a),0); if(abs(flag1-flag2)!=2)return 0; flag1=cmp((b.b-b.a)*(a.a-b.a),0),flag2=cmp((b.b-b.a)*(a.b-b.a),0); if(abs(flag1-flag2)!=2)return 0; return 1; } inline pair<double,segment> geth(point a,segment x){ point p=x.b-x.a; double len=((a-x.a)/(x.b-x.a))/p.length(); if(cmp(len,p.length())>0)return make_pair(inf,x); if(cmp(len,0)<0)return make_pair(inf,x); point h=x.a+p*(len/p.length()); segment ans=segment(a,h); return make_pair(ans.length(),ans); } inline void solve(segment a,segment b,int i,int j){ pair<double,segment> ans=min(make_pair(segment(a.a,b.a).length(),segment(a.a,b.a)),make_pair(segment(a.a,b.b).length(),segment(a.a,b.b))); ans=min({ans,make_pair(segment(a.b,b.a).length(),segment(a.b,b.a)),make_pair(segment(a.b,b.b).length(),segment(a.b,b.b))}); ans=min({ans,geth(a.a,b),geth(a.b,b)}); pair<double,segment> minn=min(geth(b.a,a),geth(b.b,a)); swap(minn.second.a,minn.second.b); ans=min(ans,minn); if(cross(ans.second,segment(point(-SS,SS),point(SS,SS))))return; if(cross(ans.second,segment(point(SS,-SS),point(SS,SS))))return; if(cross(ans.second,segment(point(-SS,-SS),point(SS,-SS))))return; if(cross(ans.second,segment(point(-SS,-SS),point(-SS,SS))))return; if(cross(ans.second,segment(point(-SS,-SS),point(SS,SS))))return; if(cross(ans.second,segment(point(-SS,SS),point(SS,-SS))))return; bool flag=cross(segment(a.a,ans.second.a),line)^cross(ans.second,line)^cross(segment(ans.second.b,b.a),line); f[i][j][flag]=f[j][i][flag]=ans.first; } int main(){ cin>>n>>S; for(int i=1;i<=n;i++){ cin>>a[i].a.x>>a[i].a.y>>a[i].b.x>>a[i].b.y; } line=segment(point(0.0,0.0),point(10000.0,10000.0*((nsc()%10000)/10000.0*pi/2))); SS=S-eps*100; a[++n]=segment(point(S,S+eps),point(S+eps,S)); a[++n]=segment(point(-S-eps,S),point(-S,S+eps)); a[++n]=segment(point(-S-eps,-S),point(-S,-S-eps)); a[++n]=segment(point(S,-S-eps),point(S+eps,-S)); for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)f[i][j][0]=f[i][j][1]=inf; for(int i=1;i<=n;i++)f[i][i][0]=0; for(int i=1;i<=n;i++){ for(int j=i+1;j<=n;j++){ solve(a[i],a[j],i,j); } } for(int k=1;k<=n;k++){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ for(int p=0;p<2;p++){ for(int q=0;q<2;q++){ f[i][j][p^q]=min(f[i][j][p^q],f[i][k][p]+f[k][j][q]); } } } } } double ans=inf; for(int i=1;i<=n;i++)ans=min(ans,f[i][i][1]); cout<<fixed<<setprecision(10)<<ans<<endl; return 0; }

__EOF__

本文作者Xttttr
本文链接https://www.cnblogs.com/Xttttr/p/17943439.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Xttttr  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示