起点/终点向每个圆的切点连边。

任意两个圆的公切点之间连边。

同一圆上相邻两个关键点之间连边。

然后Dijkstra求最短路即可,时间复杂度$O(n^3)$。

注意判边可行性的时候要忽略这条边来源的圆,可以提高精度。

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int N=510,M=1100000;
const double eps=1e-6,PI=acos(-1.0);
inline double sqr(double x){return x*x;}
struct P{double x,y;P(){x=y=0;}P(double _x,double _y){x=_x,y=_y;}P operator+(const P&v)const{return P(x+v.x,y+v.y);}P operator-(const P&v)const{return P(x-v.x,y-v.y);}P operator*(double v)const{return P(x*v,y*v);}P operator/(double v)const{return P(x/v,y/v);}double operator*(const P&v){return x*v.x+y*v.y;}double len(){return hypot(x,y);}double len_sqr(){return x*x+y*y;}P rotate(double c)const{return P(x*cos(c)-y*sin(c),x*sin(c)+y*cos(c));}P trunc(double l){return(*this)*l/len();}void read(){scanf("%lf%lf",&x,&y);}
}a[M];
int n,cnt,i,j,cp[N],pool[N][2205];double w[M];
inline bool cmp(int x,int y){return w[x]<w[y];}
inline double cross(const P&a,const P&b){return a.x*b.y-a.y*b.x;}
struct Cir{P c;double r,rr;void read(){c.read();scanf("%lf",&r);rr=sqr(r);}P point(double a)const{return P(c.x+r*cos(a),c.y+r*sin(a));}bool intersection(const P&a,const P&b){if((c-a)*(b-a)>-eps&&(c-b)*(a-b)>-eps)return sqr(cross(c-a,b-a))-rr*(b-a).len_sqr()<-eps;if((c-a).len_sqr()-rr<-eps)return 1;return (c-b).len_sqr()-rr<-eps;}
}b[N];
namespace G{
const int MAXE=M*3;
int g[M],v[MAXE],nxt[MAXE],ed;double w[MAXE],d[M];
typedef pair<double,int>P;
priority_queue<P,vector<P>,greater<P> >q;
inline void add(int x,int y,double z){v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;}
inline void ext(int x,double y){if(y+eps<d[x])q.push(P(d[x]=y,x));}
double solve(){for(i=1;i<=cnt;i++)d[i]=1e9;ext(1,0);while(!q.empty()){P t=q.top();q.pop();if(d[t.second]+eps<t.first)continue;for(i=g[t.second];i;i=nxt[i])ext(v[i],t.first+w[i]);}return d[2];
}
}
inline void add(int x,int y,int z,int u=0,int v=0){for(int i=1;i<=n;i++)if(i!=u&&i!=v)if(b[i].intersection(a[x],a[y]))return;double t=(a[x]-a[y]).len();G::add(x,y,t);if(z==2)G::add(y,x,t);
}
inline void getTangents(const P&p,const Cir&C,int v){P u=C.c-p;double dist=u.len(),ang=asin(C.r/dist);u=u.trunc(sqrt(u.len_sqr()-sqr(C.r)));a[++cnt]=u.rotate(-ang)+p;pool[v][++cp[v]]=cnt;a[++cnt]=u.rotate(ang)+p;pool[v][++cp[v]]=cnt;
}
inline void getTangents(Cir A,Cir B,int u,int v){if(A.r<B.r)swap(A,B),swap(u,v);double d=(A.c-B.c).len();double base=atan2(B.c.y-A.c.y,B.c.x-A.c.x);double ang=acos((A.r-B.r)/d);a[++cnt]=A.point(base+ang);pool[u][++cp[u]]=cnt;a[++cnt]=B.point(base+ang);pool[v][++cp[v]]=cnt;add(cnt-1,cnt,2,u,v);a[++cnt]=A.point(base-ang);pool[u][++cp[u]]=cnt;a[++cnt]=B.point(base-ang);pool[v][++cp[v]]=cnt;add(cnt-1,cnt,2,u,v);ang=acos((A.r+B.r)/d);a[++cnt]=A.point(base+ang);pool[u][++cp[u]]=cnt;a[++cnt]=B.point(PI+base+ang);pool[v][++cp[v]]=cnt;add(cnt-1,cnt,2,u,v);a[++cnt]=A.point(base-ang);pool[u][++cp[u]]=cnt;a[++cnt]=B.point(PI+base-ang);pool[v][++cp[v]]=cnt;add(cnt-1,cnt,2,u,v);
}
inline void solve(int n,int*q,const Cir&C){if(n<2)return;int i;for(i=1;i<=n;i++)w[q[i]]=atan2(a[q[i]].y-C.c.y,a[q[i]].x-C.c.x);sort(q+1,q+n+1,cmp);q[n+1]=q[1];for(i=1;i<=n;i++){double t=fabs(w[q[i]]-w[q[i+1]]);t=min(t,PI*2-t)*C.r;G::add(q[i],q[i+1],t);G::add(q[i+1],q[i],t);}
}
int main(){cnt=2;a[1].read();a[2].read();scanf("%d",&n);for(i=1;i<=n;i++)b[i].read();add(1,2,1);for(i=1;i<=n;i++){getTangents(a[1],b[i],i);add(1,cnt-1,1,i);add(1,cnt,1,i);getTangents(a[2],b[i],i);add(cnt-1,2,1,i);add(cnt,2,1,i);}for(i=1;i<=n;i++)for(j=1;j<i;j++)getTangents(b[i],b[j],i,j);for(i=1;i<=n;i++)solve(cp[i],pool[i],b[i]);return printf("%.1f",G::solve()),0;
}

  

BZOJ4739 : 定向越野相关推荐

  1. UOJ #277 BZOJ 4739 定向越野 (计算几何、最短路)

    UOJ #277 BZOJ 4739 定向越野 (计算几何.最短路) 手动博客搬家: 本文发表于20181208 14:39:01, 原地址https://blog.csdn.net/suncongb ...

  2. 无线电测向/定向越野运动中计分使用的打卡器的开发

    这个项目也是我当初折腾社团无线电测向设备时候一起开发的,首先介绍一下这个打卡器是个啥.https://item.taobao.com/item.htm?spm=a230r.1.14.1.5532434 ...

  3. 定向越野赛事成绩是否合格算法

    定向越野赛事成绩是否合格算法 定向越野赛事成绩合格条件为: 按顺序打卡号 :66.27.29.33.38.43.33.76.99 假设其中66号点位为起点,99号点位为终点,中间其他点位为打卡点位 起 ...

  4. 11行Python制作定向越野发令器

    去年在学校里办定向越野新生赛的时候,找北科的兄弟社团借了一个蜂鸣器,比赛前发现没电了,一时半会儿又找不到圆孔的古老充电器,最后在赛前1min拆了换电池才有惊无险地解决了. 这不,用 Python,0成 ...

  5. [2019.9 EOJ Monthly] B.定向越野 (贪心+模拟

    题目链接:B. 定向越野 题意: 给两个数n.p 接下来一个字符串由n个数字组成,表示n张卡片上的数字各是什么. 接下来p个询问,每个询问给出一个ki.要求对每个ki,输出将这n张卡片组成k个十进制数 ...

  6. UOJ #277 BZOJ 4739 [清华集训2016]定向越野 (计算几何、最短路)

    手动博客搬家: 本文发表于20181208 14:39:01, 原地址https://blog.csdn.net/suncongbo/article/details/84891710 哇它居然显示出图 ...

  7. 定向越野(添加任务信息和根据坐标位置触发游戏)

    1.首先获取任务地点的实际坐标值,用hashmap存储 HashMap<Integer, double[]> hashMap = new HashMap<>(); hashMa ...

  8. 山体等高线怎么看_地貌图知识(学了军事地图也会看)定向运动及野外生存入门技巧4...

    地图在古代早已显示出它的重要作用了.那么地图在现代战争中的作用又如何呢?现代战争,各军兵种协同作战,战场范围广阔,战争的突然性和破坏性增大,情况复杂多变,组织指挥复杂,对地图的依赖性更大,地图成了军队 ...

  9. 南昌计算机专业好的专科,2021年南昌计算机专业学校好不好

    2021年南昌计算机专业学校好不好 本专业要求学生具备渔业生产基本理论,并熟练掌握渔业生产各项专业技能,了解渔业相关法律法规,具备渔业企业管理知识和产品营销知识的-应用型技术人才.渔业综合技术专业大型 ...

最新文章

  1. java8 无符号_Java8包装类 新增 无符号运算方法
  2. js调试console.log使用总结图解
  3. 两个整形变量,不用中间变量进行替换!
  4. hashcode值一样对象一定相同吗_HashMap实现原理分析(面试问题:两个hashcode相同 的对象怎么存入hashmap的)...
  5. socket与文件描述符
  6. react脚手架搭建项目目录介绍
  7. 在Ubuntu下创建hadoop组和hadoop用户
  8. 商品领域ddd_为 Gopher 打造 DDD 系列:领域模型-资源库
  9. mysql利用内存表导入数据_Mysql 大量数据导入
  10. oracle ocx加载错误,flash9.ocx 加载错误解决方法
  11. Visio Professional 2016 破解教程
  12. julia安装源_Ubuntu下安装Julia
  13. 大数据与区块链的爱恨情仇,一场技术界相爱相杀的爱恋!
  14. org.hibernate.ObjectNotFoundException: No row with the given identifier exis
  15. 查询数据库空间(mysql和oracle)
  16. 路径中的“\”和“/”以及相对路径和绝对路径
  17. 设备跟服务器对接需要什么文档,『OneNET设备云平台』云平台对接服务_智能设备...
  18. github push不上去了 IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
  19. 正则表达式 同时验证手机号码和固定电话号码
  20. 容器里有10升油,现在只有两个分别能装3升和7升油的瓶子,需要将10 升油等分成2 个5 升油。编写程序,输出分油的操作过程。

热门文章

  1. My id 0 not in the peer list
  2. 升级Flash Builder 4.6中的Flash Player版本
  3. 作物叶片病害识别系统
  4. 腾讯收购黑鲨,开启游戏手机的“元宇宙时代”?
  5. 什么是跨站脚本 (XSS)?
  6. 0基础编程学python_编程零基础应当如何开始学习 Python?
  7. Duilib学习之仿酷狗开发(1)
  8. CSDN问答频道声望排行榜出炉,4月起上榜有礼
  9. 机械革命深海泰坦 X8 Pro 怎么样?测评值得买吗?
  10. 嵌入式文件系统FatFS和LittleFS对比