UOJ277【清华集训2016】定向越野(计算几何,最短路)
显然最优的路径只会经过若干条两个圆的公切线和若干段圆弧
为了方便,把起点终点看成两个半径为\(0\)的圆也行。
最烦的就是算两个圆的公切线了,一共有四条
对于靠外面的两条,我们把切线、半径和两圆心之间的线段连起来,会构成一个直角梯形。
我们可以求出两圆心连线的倾斜角,进而求出这两条切线的倾斜角,然后切线的直线方程就可以写出来了。
对于靠里面的两条,同样把切线、半径和两圆心之间的线段连起来,会出现两个相似三角形,同样可以把倾斜角求出来。
接着,判断这个切线段有没有被其它的圆挡住。
我的比较蒟蒻的做法:先用点到直线距离公式判是否与直线相交,如果相交,就要看交点是否落在线段上。把两个切点与切线的垂线的截距搞出来,判断当前圆的圆心的垂线的截距是否介于两者之间。
YL巨佬说可以通过向量来搞,算出切点到圆心这个向量在切线上的投影长度,如果小于切线段长度就说明相交了。
接着,对同一个圆上的所有切点顺次连边权为弧长的边。
最后跑一遍最短路。
细节很多,写法不尽相同,导致代码太丑了。
#include<bits/stdc++.h>
#define LL long long
#define DB double
#define RG register
#define R RG int
using namespace std;
const DB EPS=1e-9,PI=acos(-1);
const int N=503,M=8*N*N;
int n,p,he[M],ne[2*M],to[2*M];
DB x[N],y[N],r[N],w[2*M],dis[M];bool vis[M];
struct Dat{DB w;int x;inline bool operator<(Dat a)const{return w<a.w;}};
struct Nod{DB w;int x;inline bool operator<(Nod a)const{return w>a.w;}}q[M];
vector<Dat>v[N];
inline bool Eq(DB x,DB y){
return fabs(x-y)<EPS;
}
inline DB sqr(DB x){
return x*x;
}
inline DB Dis(R i,R j){
return sqrt(sqr(x[i]-x[j])+sqr(y[i]-y[j]));
}
inline DB Ang(DB a){
while(a>PI)a-=2*PI;while(a<-PI)a+=2*PI;
return a;
}
inline bool Cross(DB a,DB b,DB c,DB le,DB ri){
if(le>ri)swap(le,ri);
DB t=sqr(a)+sqr(b);
for(R i=1;i<=n;++i)
if(sqr(r[i])*t-sqr(a*x[i]+b*y[i]+c)>EPS){
DB tmp=b*x[i]-a*y[i];
if(le<=tmp&&tmp<=ri)return 1;
}
return 0;
}
inline void Add(R x,R y,DB z){
ne[++p]=he[x];to[he[x]=p]=y;w[p]=z;
ne[++p]=he[y];to[he[y]=p]=x;w[p]=z;
}
int main(){
DB sx,sy,tx,ty,a,b,c,A,B,C,tmp;
int id1,id2,p;
cin>>sx>>sy>>tx>>ty>>n;
for(R i=1;i<=n;++i)cin>>x[i]>>y[i]>>r[i];
n+=2;x[n-1]=sx;y[n-1]=sy;x[n]=tx;y[n]=ty;
for(R i=1;i<=n;++i)
for(R j=1;j<i;++j){
bool fl=0;
if(r[i]>r[j])swap(i,j),fl=1;
A=atan2(y[j]-y[i],x[j]-x[i]);
B=asin((r[j]-r[i])/Dis(i,j));
for(R tp=0;tp<=1;++tp){
C=Ang(A+B*(tp?-1:1));
if(Eq(fabs(C),PI/2))a=1,b=0;
else a=tan(C),b=-1;
tmp=Ang(C+PI/2*(tp?-1:1));
c=-a*(x[i]+r[i]*cos(tmp))-b*(y[i]+r[i]*sin(tmp));
if(!Cross(a,b,c,b*x[i]-a*y[i],b*x[j]-a*y[j])){
id1=4*(n*(i-1)+j-1)+tp,id2=4*(n*(j-1)+i-1)+tp;
v[i].push_back((Dat){tmp,id1});
v[j].push_back((Dat){tmp,id2});
Add(id1,id2,sqrt(sqr(x[i]-x[j])+sqr(y[i]-y[j])-sqr(r[j]-r[i])));
}
}
B=asin((r[j]+r[i])/Dis(i,j));
for(R tp=0;tp<=1;++tp){
C=Ang(A+B*(tp?-1:1));
if(Eq(fabs(C),PI/2))a=1,b=0;
else a=tan(C),b=-1;
tmp=sqrt(sqr(r[i])*(sqr(a)+sqr(b)));
c=tmp-a*x[i]-b*y[i];
if(!Eq(sqr(r[j])*(sqr(a)+sqr(b)),sqr(a*x[j]+b*y[j]+c)))
c=-tmp-a*x[i]-b*y[i];
if(!Cross(a,b,c,b*x[i]-a*y[i],b*x[j]-a*y[j])){
id1=4*(n*(i-1)+j-1)+tp+2,id2=4*(n*(j-1)+i-1)+tp+2;tmp=Ang(C+PI/2*(tp?-1:1));
v[i].push_back((Dat){Ang(tmp+PI),id1});
v[j].push_back((Dat){tmp,id2});
Add(id1,id2,sqrt(sqr(x[i]-x[j])+sqr(y[i]-y[j])-sqr(r[j]+r[i])));
}
}
if(fl)swap(i,j);
}
for(R i=1;i<=n;++i){
if(!v[i].size())continue;
sort(v[i].begin(),v[i].end());
Add(v[i][v[i].size()-1].x,v[i][0].x,(v[i][0].w-v[i][v[i].size()-1].w+2*PI)*r[i]);
for(R unsigned j=1;j<v[i].size();++j)
Add(v[i][j-1].x,v[i][j].x,(v[i][j].w-v[i][j-1].w)*r[i]);
}
memset(dis,127,sizeof(dis));
q[p=1]=(Nod){dis[v[n-1][0].x]=0,v[n-1][0].x};
while(p){
R x=q[1].x;pop_heap(q+1,q+p--+1);
if(vis[x])continue;vis[x]=1;
for(R y,i=he[x];i;i=ne[i])
if(dis[y=to[i]]>dis[x]+w[i])
q[++p]=(Nod){dis[y]=dis[x]+w[i],y},push_heap(q+1,q+p+1);
}
printf("%.1lf\n",dis[v[n][0].x]);
return 0;
}
UOJ277【清华集训2016】定向越野(计算几何,最短路)的更多相关文章
- UOJ #274. 【清华集训2016】温暖会指引我们前行 [lct]
#274. [清华集训2016]温暖会指引我们前行 题意比较巧妙 裸lct维护最大生成树 #include <iostream> #include <cstdio> #incl ...
- UOJ_274_[清华集训2016]温暖会指引我们前行_LCT
UOJ_274_[清华集训2016]温暖会指引我们前行_LCT 任务描述:http://uoj.ac/problem/274 本题中的字典序不同在于空串的字典序最大. 并且题中要求排序后字典序最大. ...
- UOJ 275. 【清华集训2016】组合数问题
UOJ 275. [清华集训2016]组合数问题 组合数 $C_n^m $表示的是从 \(n\) 个物品中选出 \(m\) 个物品的方案数.举个例子,从$ (1,2,3)(1,2,3)$ 三个物品中选 ...
- UOJ #269. 【清华集训2016】如何优雅地求和
UOJ #269. [清华集训2016]如何优雅地求和 题目链接 给定一个\(m\)次多项式\(f(x)\)的\(m+1\)个点值:\(f(0)\)到\(f(m)\). 然后求: \[ Q(f,n,x ...
- 【UOJ274】【清华集训2016】温暖会指引我们前行 LCT
[UOJ274][清华集训2016]温暖会指引我们前行 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很 ...
- [UOJ#276]【清华集训2016】汽水
[UOJ#276][清华集训2016]汽水 试题描述 牛牛来到了一个盛产汽水的国度旅行. 这个国度的地图上有 \(n\) 个城市,这些城市之间用 \(n−1\) 条道路连接,任意两个城市之间,都存在一 ...
- [UOJ#274][清华集训2016]温暖会指引我们前行
[UOJ#274][清华集训2016]温暖会指引我们前行 试题描述 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一 ...
- bzoj 4736 /uoj274【清华集训2016】温暖会指引我们前行 lct
[清华集训2016]温暖会指引我们前行 统计 描述 提交 自定义测试 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了 ...
- [清华集训2016]石家庄的工人阶级队伍比较坚强——三进制FWT
题目链接: [清华集训2016]石家庄的工人阶级队伍比较坚强 题目大意:有$n=3^m$个人玩石头剪刀布,共$t$轮游戏,每轮每个人要和包括自己的所有人各进行$m$次石头剪刀布.每个人在$m$轮中的决 ...
- [清华集训2016]如何优雅地求和——NTT
题目链接: [清华集训2016]如何优雅地求和 题目大意:给出一个多项式$m+1$个点值$a_{0},a_{1}...a_{m}$(其中$f(i)=a_{i}$),并给出两个数$n,x$,求$Q(f, ...
随机推荐
- Magic Stones CodeForces - 1110E (思维+差分)
E. Magic Stones time limit per test 1 second memory limit per test 256 megabytes input standard inpu ...
- CentOS 7.2 yum安装LAMP环境
https://www.linuxidc.com/Linux/2016-11/136766.htm 详见以上链接,用yum安装方便省事. 尤其注意,mysql数据要设置远程连接.
- ibatis实战之插入数据(自动生成主键)
ibatis实战之插入数据(自动生成主键) --------- 如果你将数据库设计为使用自动生成的主键,就可以使用ibatis的<selectKey>元素(该元素是<insert&g ...
- docker技术之基本命令
我们使用基本命令之前,先来普及一下操作中使用的基本概念 镜像 image 容器 container 仓库 repository 镜像 Docker 镜像是一个特殊的文件系统,除了提供容器运 ...
- 练习MD5加密jar包编写
简介 参数签名可以保证开发的者的信息被冒用后,信息不会被泄露和受损.原因在于接入者和提供者都会对每一次的接口访问进行签名和验证. 签名sign的方式是目前比较常用的方式. 第1步:接入者把需求访问的接 ...
- Linux基础命令和NAT技术
yum yellowdog updater,modified是一种用python写的基于rpm的管理工具 用于解决rpm包的依赖性 要安装编译工具 yum install gcc 库函数:静态库 ...
- 【Python3练习题 016】 猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半零一个。到第10天早上想再吃时,见只剩下一个桃子了。求第一天共摘了多少。
这题得倒着推.第10天还没吃,就剩1个,说明第9天吃完一半再吃1个还剩1个,假设第9天还没吃之前有桃子p个,可得:p * 1/2 - 1 = 1,可得 p = 4.以此类推,即可手算出. 代码思路为: ...
- 从零开始搭建VUE项目
前言: 此样板面向大型,严肃的项目,并假定您对Webpack和vue-loader有些熟悉. 请务必阅读vue-loader的常见工作流配方的文档. 如果您只想尝试vue-loader或者鞭打一个快速 ...
- java类库
Java的应用程序接口(API)以包的形式来组织,每个包提供大量的相关类.接口和异常处理类,这些包的集合就是Java的类库. Java类库可以分为两种 包名以java开始的包是Java核心包(Java ...
- spark、standalone集群 (1)
1.配置 spark/apache/org 下载解压, 安装jdk1.8 2.准备服务器 3.设置hostname 4.关闭防火墙 开启: service iptables start 关闭: ser ...