cf的地址

因为校强, "咕咕十段"队获得了EC-final的参赛资格

因为我弱, "咕咕十段"队现在银面很大

于是咕咕十段决定进行训练. 周末vp了一场, 这是赛后补题.

vp的时候想到了可以利用边界和切线, 但是没有仔细思考.

后来发现, 找到可以走的边界和切线之后, bfs一下就完事了啊.

题目给的eps限制使得我们可以合法的沿着切线和边界进行行走

关键在于找出"可以走的边界和切线"

如果一条切线在两个切点之间穿过了一个圆, 那么就不走这条切线(肯定可以走中间那个圆的某几条切线)

一条切线可以向两个切点外侧延伸, 直到与某个圆/边界相交.

主要麻烦的地方在于找圆的切线以及内外公切线. 以及我现在竟然能把直线求交写错...

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const double eps = 1e-7;
struct point{
double x, y;
point(double a = 0.0, double b = 0.0):x(a), y(b){}
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);
}
void read(){
scanf("%lf%lf",&x,&y);
}
point rot(double theta)const{
return point(x*cos(theta)-y*sin(theta), x*sin(theta) + y*cos(theta));
}
double length()const{
return sqrt(x*x+y*y);
}
point norm()const {
return point(x/length(), y/length());
}
void output(){
printf("%lf %lf",x,y);
}
}pL, pR, S, T, C[52];
double r[52];
double cross(const point &A, const point &B){
return A.x * B.y -A.y * B.x;
}
struct Line{
point S, dlt;
double tmax, tmin;
Line(){
tmax = 1e20;
tmin = -1e20;
}
Line(point s, point t){
S = s;
dlt = t - s;
tmax = 1e20;
tmin = -1e20;
}
Line(point s, point t, double t1, double t2){
S = s; dlt = t - s;
tmin = t1; tmax = t2;
}
point operator () (const double &t)const{
return S + point(dlt.x*t, dlt.y*t);
}
bool through(const point &p)const {
return fabs(cross(p-S, dlt))<eps;
}
double gett(const point &p)const{
if(fabs(p.x - S.x) > eps){
return (p.x - S.x)/(dlt.x);
}else if(fabs(p.y - S.y)>eps){
return (p.y - S.y)/(dlt.y);
}else{
return 0;
}
}
bool contain(const point &p)const{
if(fabs(cross(p-S, dlt))>eps)return false;
double t = gett(p);
return t>=tmin-eps&&t<=tmax+eps;
}
point getp(double t)const{
return point(S.x+t*dlt.x, S.y+t*dlt.y);
}
void output(){
S.output();(S+dlt).output();
}
}L[6000];
Line tangent(point P, point C, double r, int flag){
double theta = acos(r/(P-C).length());
point v = (P-C).norm();
v = point(v.x*r, v.y*r);
v = v.rot(flag*theta);
point T = C + v;
return Line(P, T);
}
Line tangent_out(point C1, double r1, point C2, double r2, int flag){
if((fabs(r1-r2))<eps){
point v = (C1-C2).norm();
v = point(v.x * r1, v.y * r1);
v = v.rot(flag*acos(-1)/2);
return Line(C1+v, C2+v);
}else{
if(r1>r2){
swap(C1, C2);
swap(r1, r2);
}
//r1<r2
//r1/r2 = (l1)/(l2), l2-l1 = length(C1-C2)
double L = (C1 - C2).length();
L = L * r2/(r2-r1);
point v = (C1-C2).norm();
double theta = flag * acos(r2/L);
v = v.rot(theta);
return Line(C1 + point(v.x*r1, v.y*r1), C2 + point(v.x*r2, v.y*r2));
}
}
Line tangent_in(point C1, double r1, point C2, double r2, int flag){
point v = (C2 - C1);
point P = C1 + point(v.x*r1/(r1+r2), v.y*r1/(r1+r2));
double theta = flag*acos(r1/(P-C1).length());
v = v.norm().rot(theta);
return Line(C1 + point(v.x*r1, v.y*r1), C2 - point(v.x*r2,v.y*r2));
}
int cnt_lines = 0, cnt_lines2 = 0;
point intersect(const Line &L1, const Line &L2){
double C = cross(L1.dlt, L2.dlt);
if(fabs(C)<eps)return point(1e20, 1e20);
else{
double t = cross(L1.S - L2.S, L2.dlt)/cross(L2.dlt, L1.dlt);
return L1(t);
}
}
double mult(const point &P1, const point &P2){
return P1.x*P2.x + P1.y*P2.y;
}
bool between(point P, Line &L){
point S = L.S, T = L.S + L.dlt;
return mult(S-P, T-P) < -eps;
}
bool intersect(Line &L, point C, double r){
double dis = fabs(cross(C-L.S, L.dlt))/L.dlt.length();
if(dis > r - eps)return false;
double theta = acos(dis/r);
int flag = cross(C-L.S, L.dlt) > eps ? (1) : (-1);
point v = L.dlt.norm().rot(flag * acos(-1)/2 + theta);
point p = C + point(v.x*r, v.y*r);
if(between(p, L)){
return true;
}else{
double t = L.gett(p);
if(t < 0 && t > L.tmin){
L.tmin = t;
}
if(t > 0 && t < L.tmax){
L.tmax = t;
}
v = L.dlt.norm().rot(flag * acos(-1)/2 - theta);
p = C + point(v.x*r, v.y*r);
t = L.gett(p);
if(t < 0 && t > L.tmin){
L.tmin = t;
}
if(t > 0 && t < L.tmax){
L.tmax = t;
}
return false;
}
}
int N;
bool visited[6000];
int pre[6000], dis[6000];
int q[6000];
void output(int x, int cnt){
if(pre[x] == 0){
printf("%d\n",cnt);
}else{
output(pre[x], cnt+1);
point p = intersect(L[x], L[pre[x]]);
p.output();printf("\n");
}
}
void bfs(){
int head = 0, tail = 0;
visited[0] = true; dis[0] = 0;//S
for(int i = 1; i <= cnt_lines2; ++i){
if(L[i].contain(S)){
pre[i] = 0; dis[i] = 1;
visited[i] = true;
q[tail++] = i;
}
}
while(head!=tail){
int x = q[head++];
if(L[x].contain(T)){
output(x, 0);
break;
}else{
for(int i=1;i<=cnt_lines2;++i){
if(!visited[i]){
point p = intersect(L[i],L[x]);
if(L[i].contain(p)&&L[x].contain(p)){
q[tail++] = i;
visited[i] = true;
pre[i] = x;
dis[i] = dis[x] + 1;
}
}
}
}
}
}
int main(){
scanf("%d",&N);
pL.read();pR.read();
S.read();T.read();
for(int i = 1;i <= N;++i){
C[i].read();scanf("%lf", r+i);
}
L[++cnt_lines] = Line(S, T);
for(int i = 1;i <= N;++i){
L[++cnt_lines] = tangent(S, C[i], r[i], 1);
L[++cnt_lines] = tangent(S, C[i], r[i], -1);
L[++cnt_lines] = tangent(T, C[i], r[i], 1);
L[++cnt_lines] = tangent(T, C[i], r[i], -1);
}
for(int i = 1;i <= N;++i){
for(int j = i + 1;j <= N;++j){
L[++cnt_lines] = tangent_out(C[i], r[i], C[j], r[j], 1);
L[++cnt_lines] = tangent_out(C[i], r[i], C[j], r[j],-1);
L[++cnt_lines] = tangent_in(C[i], r[i], C[j], r[j], 1);
L[++cnt_lines] = tangent_in(C[i], r[i], C[j], r[j],-1);
}
}
for(int i=1;i<=cnt_lines;++i){
bool flag = true;
for(int j = 1;j <= N;++j){
if(intersect(L[i], C[j], r[j])){
flag = false;break;
}
}
if(flag){
L[++cnt_lines2] = L[i];
}
}
L[++cnt_lines2] = Line(point(pL.x, pL.y), point(pL.x, pR.y), 0, 1);
L[++cnt_lines2] = Line(point(pR.x, pL.y), point(pR.x, pR.y), 0, 1);
L[++cnt_lines2] = Line(point(pL.x, pL.y), point(pR.x, pL.y), 0, 1);
L[++cnt_lines2] = Line(point(pL.x, pR.y), point(pR.x, pR.y), 0, 1);
for(int i=1;i<=cnt_lines2 - 4;++i){
for(int j=cnt_lines2 - 3;j<=cnt_lines2;++j){
point p = intersect(L[i], L[j]);
double t = L[i].gett(p);
if(t<0&&t>L[i].tmin){
L[i].tmin = t;
}
if(t>0&&t<L[i].tmax){
L[i].tmax = t;
}
}
}
bfs();
return 0;
}

Asia Jakarta Regional Contest 2019 I - Mission Possible的更多相关文章

  1. 2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred)

    2019-2020 ICPC, Asia Jakarta Regional Contest (Online Mirror, ICPC Rules, Teams Preferred) easy: ACE ...

  2. 2019-2020 ICPC, Asia Jakarta Regional Contest

    目录 Contest Info Solutions A. Copying Homework C. Even Path E. Songwriter G. Performance Review H. Tw ...

  3. 2019-2020 ICPC, Asia Jakarta Regional Contest H. Twin Buildings

    As you might already know, space has always been a problem in ICPC Jakarta. To cope with this, ICPC ...

  4. 2018 ICPC Asia Jakarta Regional Contest

    题目传送门 题号 A B C D E F G H I J K L 状态 Ο . . Ο . . Ø Ø Ø Ø . Ο Ο:当场 Ø:已补 .  :  待补 A. Edit Distance Thin ...

  5. 2019-2020 ICPC, Asia Jakarta Regional Contest C. Even Path

    Pathfinding is a task of finding a route between two points. It often appears in many problems. For ...

  6. 2019-2020 ICPC, Asia Jakarta Regional Contest A. Copying Homework

    Danang and Darto are classmates. They are given homework to create a permutation of N integers from  ...

  7. 模拟赛小结:2019-2020 ICPC, Asia Jakarta Regional Contest

    比赛链接:传送门 离金最近的一次?,lh大佬carry场. Problem A. Copying Homework 00:17(+) Solved by Dancepted 签到,读题有点慢了.而且配 ...

  8. 2016 Asia Jakarta Regional Contest L - Tale of a Happy Man UVALive - 7722

    UVALive - 7722 一定要自己做出来!

  9. 2016 Asia Jakarta Regional Contest A - Confusing Date Format UVALive 7711 【模拟题】

    A - Confusing Date Format 题目大意:就是有六种日期格式,给你一个字符串,判断它能组成多少种可能的日期. 第一次WA是:1.没有判重,2.没有特判题目要求的数据,3.判断天数时 ...

随机推荐

  1. CentOS7-Docker容器入门

    Docker由三大部分组成 基础镜像---->中间件---->最后生成应用镜像一个镜像可以给多个进程使用! Docker是什么 Docker是一个改进的容器技术.具体的“改进”体现在,Do ...

  2. RT1052 BootLoader总结

    RT1052 BootLoader总结‍ 概述 Bootloader涉及到的RT1052单片机资源有:Cache,ram,外部SDRAM,ARM7汇编指令,外部dataFlash. 升级功能涉及到的其 ...

  3. Java面试题及答案汇总(一)

    Java 基础 1. JDK 和 JRE 有什么区别? JDK:Java Development Kit 的简称,java 开发工具包,提供了 java 的开发环境和运行环境. JRE:Java Ru ...

  4. .NET-异步操作

    感觉可以用于log日志的东西,这个东西他还是会走的但是不会影响你下一步的操作,你下一步还是正常怎么操作就怎么操作! 这样可以给用户免掉一些没必要的等待. static void Main(string ...

  5. 玩转dockerfile

    镜像的缓存特性 Docker 会缓存已有镜像的镜像层,构建新镜像时,如果某镜像层已经存在,就直接使用,无需重新创建. 举例说明.在前面的 Dockerfile 中添加一点新内容,往镜像中复制一个文件: ...

  6. 2019 浪潮java面试笔试题 (含面试题解析)

      本人5年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.浪潮等公司offer,岗位是Java后端开发,因为发展原因最终选择去了浪潮,入职一年时间了,之前面试了很多家公 ...

  7. 解决Ajax前台中文传到后台出现中文乱码

    遇到的问题是: 前台利用Ajax, get方式向后台发送中文数据出现乱码. 解决办法是前台两次编码, 后台一次解码即可. 前台jsp文件 1 var text = "张三"; 3 ...

  8. 复杂dic的文件化存储和读取问题

    今天遇到一个难题.整出一个复杂的dic,里面不仅维度多,还含有numpy.array.超级复杂.过程中希望能够存储一下,万一服务器停了呢?万一断电了呢? 结果存好存,取出来可就不是那样了.网上搜索了很 ...

  9. Spring 在xml文件中配置Bean

    Spring容器是一个大工厂,负责创建.管理所有的Bean. Spring容器支持2种格式的配置文件:xml文件.properties文件,最常用的是xml文件. Bean在xml文件中的配置 < ...

  10. 使用Prometheus针对自己的服务器采集自定义的参数

    用一个简单的例子来说明. 我用express和http搭了一个最简单的服务器,监听在8081端口上. 在metrics endpoint上,我会打印出这个服务器从启动至今,服务了多少次请求.这里我只是 ...