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. Sqlite清空表数据以及重新设置主键操作

    Sqlite清空表数据以及重新设置主键操作 delete from 表名; //清空数据 update sqlite_sequence SET seq = 0 where name ='表名';//自 ...

  2. (八)pdf的构成之文件体(page属性)

    资源(Resources) 类型:字典 属性: Font :一个字典,内部是该资源包含的各个字体的名称(字体名称F开头) ProcSet :该资源中使用图画还是文字,可选 /PDF /Text /Im ...

  3. Linux Shell/Bash wildcard通配符、元字符、转义符使用

    说到shell通配符(wildcard),大家在使用时候会经常用到.下面是一个实例: 1   1 2 3 4 [chengmo@localhost ~/shell]$ ls a.txt  b.txt  ...

  4. tf.tile()函数的用法

    y = tf.tile(tf.range(2, dtype=tf.int32)[:, tf.newaxis], [2,3]) # tf.tile(input,[a,b]) 输入数据,按照对应维度将矩阵 ...

  5. mysql-表关系介绍(应用较多)

    目录 表之间的关系(重点) foreign key (外键) 级联操作 (cascade) 两种级联操作 外键的使用 多对一(一对多) 多对多 一对一关系 表之间的关系(重点) foreign key ...

  6. Python进阶(十)----软件开发规范, time模块, datatime模块,random模块,collection模块(python额外数据类型)

    Python进阶(十)----软件开发规范, time模块, datatime模块,random模块,collection模块(python额外数据类型) 一丶软件开发规范 六个目录: #### 对某 ...

  7. sdcard不可执行.

    Possibly you placed it on your sdcard -- which is mounted with the noexec flag. You either need to m ...

  8. 【初识算法】- AC算法

    原文地址:https://www.cnblogs.com/jily/p/6250716.html 一.原理 AC自动机首先将模式组记录为Trie字典树的形式,以节点表示不同状态,边上标以字母表中的字符 ...

  9. webpack-dev-server提示css模块解析失败,但已经装了css-loader

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/a117616/article/detai ...

  10. redis设置远程连接

    1.修改redis服务器的配置文件 本机安装的redis-4.0.14默认的配置文件 redis.conf 设置 绑定本机地址:bind 127.0.0.1 开启保护模式:protected-mode ...