当前位置: 首页 > ds >正文

洛谷 P2452 [SDOI2005] 屠龙传说-屠龙枪卷

题目描述

先知看到修玛取回的药草,满意地点了点头。

他对修玛说:“跟我来”。

修玛顺从地跟着先知走到了他的房间里。先知的房间很大,四周满是书架,整整齐齐地摆放着一排排书籍。房间中间的圆桌上摆放着一个巨大的水晶球,它发出的荧光照亮了整个房间。

先知走到一排书架前,从中抽出一本薄薄的书来。这本书看起来十分古老,纸张都变成了黄色,有的地方已经发黑。修玛想,这本书的历史大概有好几百年了吧。

先知示意修玛坐下,他翻开手中的书,对修玛说道:“我已经研究这本书很久了。它是用一种古老的文字写成的,记载了一个十分古老的传说。书中提到,普通的武器是无法伤害巨龙的,只有诸神合力锻造的屠龙枪才能消灭它。为了防止屠龙枪被滥用,神把它封印在卡基思山上,只有拥有超人的勇气、力量和智慧的人才能解开这个封印。千百年来,很多人都想得到屠龙枪的力量,然而从没有人成功过。我查阅了所有有关屠龙枪的记载,悉心地研究那些资料,得知屠龙枪被封印在山顶的神殿中,而要解开这道封印,就必须把神殿中的一块巨大的圆石推到神殿祭坛的中心,然后念出解开封印的咒语。”

修玛问道:“那句咒语应该已经失传了吧?”“不,恰恰相反。”先知说,“这句咒语一直记载在这本书中,并被完好地保存下来。”“那么,剩下的只是把圆石推到祭坛的中心了。”修玛自信地笑了。然而先知却摇了摇头,“不,修玛,事情没有你想象的那么简单。爬上卡基思山就不是一件容易的事。它高耸入云,四周都是光秃秃的石壁,几乎没有落脚的地方。只有真正的勇士才能爬得上去。那块圆石也不是那么容易就能推动的,非得有超常的力量不可。这些东西,修玛你都有。但如果仅仅只有这些,那么屠龙枪早已被人拿到手了。书中不是说了么,要有勇气、力量和智慧。智慧才是真正的关键。如果在固定时间内不能把那块圆石推到祭坛的中心,那么圆石便会自动滚回原处,同时推石的人将永远无法再次推动这块圆石。而且不管你用多大力气推,这块圆石都不可能滚动得像你希望的那样快,我估计只有按照最短路线去推这块圆石,才能在固定时间内把它推到祭坛中心。神殿中又有着大大小小的石柱,有些石柱与石柱之间的空隙很小,根本就推不过去。正因为这种种困难,才没有人能够从神殿中取走屠龙枪。”

修玛沉默了一会儿,说:“不管如何,我也要去试一试。如果我不能拿到屠龙枪,就没有人能够拿到它了。”

先知点了点头,说:“去吧,修玛。记住,用你的智慧。”

修玛骑马奔驰了十天十夜,终于来到了卡基思山脚下。正如先知所说的那样,这座山根本就没有路可以上去,甚至找不到可以落脚的地方。然而修玛凭着他的勇气以及熟练的技巧,爬上了山顶。

当他走进神殿,一眼就看到了那块巨大的圆石。修玛该怎么做,才能把圆石推到祭坛的中心呢?

任务

你的任务是计算出把圆石推到祭坛中心的最短路线长度。

所谓推到祭坛中心是指圆石的中心与祭坛中心重合。

圆石中心的初始位置以及祭坛中心的位置是已知的。圆石半径为 �R,它可以朝着任意方向滚动。洞中所有石柱均为正四棱柱,大小不一。

在推动圆石的过程中,要求圆石中心与所有石柱的距离均不小于 �R,否则圆石将被石柱阻挡而不能继续滚动。

输入格式

第一行包含了五个实数,依次表示圆石中心的初始位置的 �x 坐标、�y 坐标、圆石半径 �R、祭坛中心的位置 (�,�)(x,y)。

第二行包含一个整数 �n,表示神殿中石柱的数目。

接下来 �n 行,每行包含三个实数 (��,��,��)(xi​,yi​,ri​),给出了一根石柱的信息,依次表示第 �i 根石柱左下角 �x 坐标、�y 坐标以及该石柱的边长。

数据输入所有实数均精确到 22 位小数,范围在 00 到 10001000 之内。

输出格式

输出仅包含一个实数,表示把圆石推到祭坛中心的最短路线长度,输出结果保留到两位小数。

若不存在一条把圆石推到祭坛中心的路,输出 0.00

输入输出样例

输入 #1复制

0 0 10 30 40
1
10 10 10

输出 #1复制

57.93

说明/提示

数据范围及约定

对于全部数据,满足 0≤�≤200≤n≤20。


修玛思索良久,果断地走到圆石旁边,用力推动这块巨石。圆石在修玛的推动下,缓缓地滚动起来。修玛时不时地调整着推动的角度,以使巨石朝着自己希望的方向滚动。终于,“卡嗒”的一声,圆石安安稳稳地滚到了祭坛的中心。一束光从神殿顶上直射而下,笼罩了整个祭坛。修玛对着祭坛,大声地念出了解开封印的咒语。顿时,祭坛开始颤动,中间的圆石也随着摇摆不定。突然间,整块圆石完全爆裂开来,在祭坛的中心,出现了一柄长枪。枪身上闪烁着神圣的光芒,令人惊羡不已。修玛走上前去,拔起了这柄枪。他感到一股强大的力量从手上传了过来。修玛随手把枪一挥,只听得“哗啦”一声,一根巨大的石柱应声四分五裂了。修玛又惊又喜,他知道这一定就是屠龙枪。

本题给出若干个正方形障碍以及一个圆,求把圆推到目标位置的最短距离。

首先可以把这些障碍向外扩张 �r,形成一个类似

的图形,拆解开来就是 4 个圆加上俩矩形,将题意转化为从起点出发不穿过任意障碍到达终点的最短路。

先把样例画出来:

发现实际上可能走的路径分为四类:

  1. 点到圆上的切点
  2. 点直接到另一点
  3. 同一圆上的点相互走
  4. 圆到另一圆上的点

其中第 4 类实际上就是找到一条线段同时切两个圆,如下图的 ��CD 以及 ��FG。

可以发现 ��⊥��AC⊥AB。

令 ��AB 中点为 �O,那么有 ��FO 切圆 �A 于 �F、��GO 切圆 �B 于 �G,套用 1 的方法即可找到 ��FG。

将所有的可能路径都 check 一遍,建出图跑最短路即可。要 check 的是一个线段或者一段圆弧是否穿过某个障碍。

线段是否穿过矩形内部

首先特判掉线段端点在矩形内部以及线段与矩形某条边重合的情况,然后再算出该线段与矩形四条边的交点个数 �x,当 �=2x=2 时线段穿过矩形。

线段是否穿过圆内部

求出线段到圆心的距离与半径比较一下即可。

圆弧是否穿过矩形内部

这个得画一画。令圆弧端点为 �,�l,r(逆时针),称一个点是合法的当且仅当该点不在 ��→ol 和 ��→or 组成的角内。

首先把圆弧上的端点在矩形内部特判掉,按照矩形端点在圆内部的点数 �m 以及圆心是否在矩形内部分讨。

  • 圆心在矩形内部

    若有一个端点不在圆内部或圆上且该端点不合法,则圆弧穿过矩形内部。

  • �=4m=4

    圆包含了矩形,肯定不穿过。

  • �=1m=1

    当 �1L1​ 不合法时圆弧穿过矩形。

  • �=2m=2

    当上面两个点有一个不合法时圆弧穿过矩形。

  • �=3m=3

    剩下的那个点不合法就穿过。

  • �=0m=0

    由于只会出现 1441​ 圆,故而不会出现只会包含一条边的情况,必定不穿过。

圆弧是否穿过圆内部

还是先特判两圆相离、圆弧端点在圆内的情况,若此时另一圆的圆心不合法则穿过。

代码如下:

#pragma GCC optimize("O2")
#include<bits/stdc++.h>
#define db double
#define seg(x,y) (line){x,y}
#define mk(x,y) (point){x,y}
using namespace std;
const int N=2e6+50;
const db eps=1e-6,pi=acos(-1),inf=1e32;void write(db x,char t='\n'){if(fabs(x)<eps)x=0;printf("%.2lf%c",x,t);}
template<class T, class... Args> inline void write(T x, Args... args) { write(x, ' '), write(args...); }struct point
{db x,y,k;friend point operator+(point a,point b){return mk(a.x+b.x,a.y+b.y);}friend point operator-(point a,point b){return mk(a.x-b.x,a.y-b.y);}friend point operator*(point a,db b){return mk(a.x*b,a.y*b);}db Atan2(){return atan2(y,x);}friend bool operator<(point a,point b){return a.k==b.k?a.x<b.x:a.k<b.k;}db len(){return sqrt(x*x+y*y);}void pre(point o){k=atan2(y-o.y,x-o.x);}friend bool operator==(point a,point b){a=a-b;return (fabs(a.x)<=eps)&(fabs(a.y)<=eps);}friend db dis(point a,point b){return (a-b).len();}friend point tolen(point a,db t){return a*(t/a.len());}void input(){scanf("%lf%lf",&x,&y);}void print(){printf("%.2lf %.2lf\n",x,y);}db angle(){return (y<0)*pi+atan(y/x);}point rotate(db t){return mk(x*cos(t)-y*sin(t),y*cos(t)+x*sin(t));}
}z,O;bool equiv(db x,db y){return fabs(x-y)<=eps;}
db dot(point a,point b){return a.x*b.x+a.y*b.y;}
db cross(point a,point b){return a.x*b.y-a.y*b.x;}
db angle(point a,point b){if(a==z||b==z)return 0;return acos(dot(a,b)/a.len()/b.len());}
point mirror(point a,point b){return b+(b-a);}
bool zcmp(db x){return fabs(x)<=eps;}struct line
{point a,b;point vec(){return b-a;}bool include(point x,int f=1){if(f)return zcmp(cross(a-x,b-x));if(!zcmp(cross(a-x,b-x)))return 0;return (min(a.x,b.x)<=x.x+eps)&(max(a.x,b.x)+eps>=x.x)&(min(a.y,b.y)<=x.y+eps)&(max(a.y,b.y)+eps>=x.y);}
};bool onright(line a,point s){return cross(a.a-s,a.b-s)<=0;}int relation(line a,line b)
{if(a.include(b.a)&&a.include(b.b))return -1;if(zcmp(cross(a.vec(),b.vec())))return 0;return 1;
}point intersect(line a,line b)
{db s1=cross(b.a-a.a,b.b-a.a),s2=cross(b.b-a.b,b.a-a.b);return a.a+(a.b-a.a)*(s1/(s1+s2));
}point perpend(line a,point b)
{point d=b+(a.vec()).rotate(pi/2);return intersect(a,(line){b,d});
}db dis(line a,point b,int f=1)
{if((a.a-a.b)==z)return -1;point p=perpend(a,b);if(a.include(p,0)||f)return dis(b,p);return min(dis(a.a,b),dis(a.b,b));
}int n,m,cs,cc;
point to,p[N];struct circle
{point o;db r;bool in(point x){return r>dis(x,o)+eps;}bool in(line x){return dis(x,o,0)+eps<r;}
}c[N],o;int intersectnum(line a,line b)
{if(relation(a,b)!=1)return 0;point x=intersect(a,b);return (a.include(x,0)&&b.include(x,0));
}struct square
{point a,dx,dy;bool in(point x){if(x.x>a.x+eps&&eps+x.x<(a+dx+dy).x&&x.y>a.y+eps&&eps+x.y<(a+dx+dy).y)return 1;return 0;}bool in(line x){if(in(x.a)||in(x.b))return 1;if(relation(seg(a,a+dx),x)==-1||relation(seg(a,a+dy),x)==-1||relation(seg(a+dx,a+dx+dy),x)==-1||relation(seg(a+dy,a+dx+dy),x)==-1)return 0;if(x.include(a)||x.include(a+dx)||x.include(a+dy)||x.include(a+dx+dy))return 0;int val=intersectnum(seg(a,a+dx),x)+intersectnum(seg(a,a+dy),x)+intersectnum(seg(a+dy,a+dy+dx),x)+intersectnum(seg(a+dx,a+dx+dy),x);return val==2;}bool chk(circle x){return x.in(seg(a,a+dx))|x.in(seg(a,a+dy))|x.in(seg(a+dx,a+dx+dy))|x.in(seg(a+dy,a+dx+dy));}
}s[N];bool chk(point x)
{for(int i=1;i<=cc;i++)if(c[i].in(x))return 1;for(int i=1;i<=cs;i++)if(s[i].in(x))return 1;return 0;
}bool chk(line x)
{for(int i=1;i<=cc;i++)if(c[i].in(x))return 1;for(int i=1;i<=cs;i++)if(s[i].in(x))return 1;return 0;
}bool chk(point o,point l,point r,point x)
{return onright(seg(o,r),x)&&!onright(seg(o,l),x);
}bool chk(circle o,point l,point r,circle x)
{if(dis(o.o,x.o)>=o.r+x.r)return 0;if(x.in(l)||x.in(r))return 1;return chk(o.o,l,r,x.o);
}bool chk(circle o,point l,point r,square x)
{if(x.in(l)||x.in(r))return 1;point a=x.a,b=a+x.dx,c=a+x.dy,d=a+x.dx+x.dy,t[6],q[6];int m=0,k=0;if(x.in(o.o)){if(dis(a,o.o)>o.r&&chk(o.o,l,r,a))return 1;if(dis(b,o.o)>o.r&&chk(o.o,l,r,b))return 1;if(dis(c,o.o)>o.r&&chk(o.o,l,r,c))return 1;if(dis(d,o.o)>o.r&&chk(o.o,l,r,d))return 1;return 0;}if(o.in(a))t[++m]=a;else q[++k]=a;if(o.in(b))t[++m]=b;else q[++k]=b;if(o.in(c))t[++m]=c;else q[++k]=c;if(o.in(d))t[++m]=d;else q[++k]=d;if(m==4)return 0;if(m==1)return chk(o.o,l,r,t[1]);if(m==2)return chk(o.o,l,r,q[1])|chk(o.o,l,r,q[2]);if(m==3)return chk(o.o,l,r,q[1]);if(!x.chk(o))return 0;return chk(o.o,l,r,a)+chk(o.o,l,r,b)+chk(o.o,l,r,c)+chk(o.o,l,r,d)>1;
}bool chk(circle o,point l,point r)
{for(int i=1;i<=cc;i++)if(chk(o,l,r,c[i]))return 1;for(int i=1;i<=cs;i++)if(chk(o,l,r,s[i]))return 1;return 0;
}db dis(circle o,point l,point r)
{r=r-o.o,l=l-o.o;return o.r*angle(l,r);
}struct edge
{int u,v;db w;int nxt;
}e[N];struct node
{int x;db w;friend bool operator<(node a,node b){return a.w>b.w;}
};int head[N],cnt;
db d[N];void add(int u,int v,db w)
{e[++cnt]=(edge){u,v,w,head[u]};head[u]=cnt;e[++cnt]=(edge){v,u,w,head[v]};head[v]=cnt;
}void dij()
{priority_queue<node>q;for(int i=1;i<=m;i++)d[i]=inf;d[1]=0;q.push((node){1,0});while(!q.empty()){int x=q.top().x;db w=q.top().w;q.pop();if(!equiv(w,d[x]))continue;for(int i=head[x];i;i=e[i].nxt){int v=e[i].v;if(d[v]>d[x]+e[i].w){d[v]=d[x]+e[i].w;q.push((node){v,d[v]});}}}if(equiv(d[2],inf))d[2]=0;cerr<<fixed<<setprecision(2)<<d[2]<<' ';
}point dx=mk(1,0),dy=mk(0,1);int find(circle o,point&a,point&b,point x)
{if(o.in(x))return 0;x=x-o.o;point rx=x;db angle=acos(o.r/x.len());x=tolen(x.rotate(angle),o.r);a=x+o.o;x=mirror(x,perpend(seg(O,rx),x));b=x+o.o;return 1;
}int h[N];bool cmp(int a,int b)
{return p[a]<p[b];
}vector<int>in[N];main()
{// freopen("in.txt","r",stdin);// freopen("out.txt","w",stdout);o.o.input(),scanf("%lf",&o.r);to.input();scanf("%d",&n);p[++m]=o.o,p[++m]=to;for(int i=1;i<=n;i++){point x;db r;x.input();scanf("%lf",&r);p[++m]=x-dx*o.r;p[++m]=x-dy*o.r;c[++cc]=(circle){x,o.r};in[cc].push_back(m),in[cc].push_back(m-1);x=x+dx*r;p[++m]=x+dx*o.r;p[++m]=x-dy*o.r;c[++cc]=(circle){x,o.r};in[cc].push_back(m),in[cc].push_back(m-1);x=x+dy*r;p[++m]=x+dx*o.r;p[++m]=x+dy*o.r;c[++cc]=(circle){x,o.r};in[cc].push_back(m),in[cc].push_back(m-1);x=x-dx*r;p[++m]=x-dx*o.r;p[++m]=x+dy*o.r;c[++cc]=(circle){x,o.r};in[cc].push_back(m),in[cc].push_back(m-1);x=x-dy*r;s[++cs]=(square){x-dx*o.r,dx*(2*o.r+r),dy*r};s[++cs]=(square){x-dy*o.r,dx*r,dy*(2*o.r+r)};}for(int i=1;i<=cc;i++)if(equiv(dis(p[1],c[i].o),c[i].r))in[i].push_back(1);for(int i=1;i<=cc;i++)if(equiv(dis(p[2],c[i].o),c[i].r))in[i].push_back(2);if(zcmp(o.r))cc=0;int mm=m;for(int i=1;i<=cc;i++)for(int j=i+1;j<=cc;j++){if(seg(O,dx).include(c[j].o-c[i].o))continue;if(seg(O,dy).include(c[j].o-c[i].o))continue;point x=c[j].o-c[i].o;x=x.rotate(pi/2);x=tolen(x,c[i].r);point A,B,C,D;A=c[i].o+x,B=c[i].o-x;C=c[j].o+x,D=c[j].o-x;if(!chk(seg(A,C)))p[++m]=A,p[++m]=C,add(m-1,m,dis(A,C)),in[i].push_back(m-1),in[j].push_back(m);if(!chk(seg(B,D)))p[++m]=B,p[++m]=D,add(m-1,m,dis(B,D)),in[i].push_back(m-1),in[j].push_back(m);}for(int i=1;i<=cc;i++)for(int j=i+1;j<=cc;j++){point x=c[j].o-c[i].o;x=c[i].o+tolen(x,x.len()*c[i].r/(c[i].r+c[j].r));point A,B,C,D;if(!find(c[i],A,B,x))continue;if(!find(c[j],C,D,x))continue;if(!zcmp(cross(A-x,C-x)))swap(A,B);if(!chk(seg(A,C)))p[++m]=A,p[++m]=C,add(m-1,m,dis(A,C)),in[i].push_back(m-1),in[j].push_back(m);if(!chk(seg(B,D)))p[++m]=B,p[++m]=D,add(m-1,m,dis(B,D)),in[i].push_back(m-1),in[j].push_back(m);}for(int i=1;i<=mm;i++)for(int j=1;j<=cc;j++)if(dis(p[i],c[j].o)>c[j].r){point x,y;if(!find(c[j],x,y,p[i]))continue;if(!seg(O,dx).include(p[i]-x)&&!seg(O,dy).include(p[i]-x)&&!chk(seg(p[i],x)))p[++m]=x,add(i,m,dis(p[i],x)),in[j].push_back(m);if(!seg(O,dx).include(p[i]-y)&&!seg(O,dy).include(p[i]-y)&&!chk(seg(p[i],y)))p[++m]=y,add(i,m,dis(p[i],y)),in[j].push_back(m);}for(int i=1;i<=cc;i++){int top=0;for(auto j:in[i])h[++top]=j,p[j].pre(c[i].o);sort(h+1,h+1+top,cmp);h[top+1]=h[1];for(int j=1;j<=top;j++)if(!chk(c[i],p[h[j]],p[h[j+1]]))add(h[j],h[j+1],dis(c[i],p[h[j]],p[h[j+1]]));}for(int i=1;i<=mm;i++)for(int j=i+1;j<=mm;j++)if(!chk(seg(p[i],p[j])))add(i,j,dis(p[i],p[j]));dij();
}

拜拜! 

http://www.xdnf.cn/news/11121.html

相关文章:

  • 2022-04-30 Unity核心2——Sprite
  • 10种用于渗透测试的漏洞扫描工具有哪些_渗透测试和漏洞扫描区别_渗透漏洞分级工具
  • Android2.2快速入门
  • 13种网页QQ代码
  • MFC自绘入门(一)
  • 华硕电脑无法安装Ubuntu 11.04(10.10同)
  • 作为程序员,我都逛了哪些技术网站?(收藏篇)
  • 将小游戏打包成单一exe文件的原理及应用
  • 修改固态硬盘的物理序列号_电脑突然断电,固态硬盘无法识别怎么办?
  • tracert 路由跟踪
  • Authorware使用案例:DirectMediaXtra制作内部媒体播放器
  • 2024年九个简单易用的wordpress主题模板网站推荐
  • 网络常用命令:tracert(非常详细)零基础入门到精通,收藏这一篇就够了
  • 一看就懂的积分电路分析
  • struts2简介
  • 3Ds max材质制作教程:创建金、银、铜金属材质
  • 十款超高人气FTP客户端软件横评(一)
  • 前端使用marquee标签实现提示语滚动效果
  • UIColor 常用方法
  • XML文件基础应用
  • MVC5 PartialView(部分视图)和模板页
  • 连接器(Netlink Connector)及其应用
  • 【python】Python语言程序设计/嵩天老师入门课程笔记整理
  • patch补丁文件格式
  • 山东大学高频电子线路实验三 正弦波振荡器实验详解_三点式正弦波振荡器实验报告(1)
  • [转]游戏外挂开发
  • python之torchlight使用_《火炬之光2》功能型MOD制作教程
  • 常用的开源网站框架
  • 计算机毕业设计Java彩票在线购买系统(源码+系统+mysql数据库+lw文档)
  • JSP自定义标签开发(五)——标签类获取 request 、 session