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. spring整合mybatis报.UnsatisfiedDependencyException错误

    tomcat启动报org.springframework.beans.factory.UnsatisfiedDependencyException:错误 org.springframework.bea ...

  2. Java多线程编程(4)--线程同步机制

    一.锁 1.锁的概念   线程安全问题的产生是因为多个线程并发访问共享数据造成的,如果能将多个线程对共享数据的并发访问改为串行访问,即一个共享数据同一时刻只能被一个线程访问,就可以避免线程安全问题.锁 ...

  3. 微信公众号开发 token 验证程序

    <?php traceHttp(); define("TOKEN", "gmll001"); $wechatObj = new wechatCallbac ...

  4. day26——tyoe元类与object的联系、反射、函数与方法的区别、双下方法

    day26 type元类与object联系 type 获取对象从属于的类 python 中一切皆对象, 类在某种意义上也是一个对象,python中自己定义的类,以及大部分内置类,都是由type元类(构 ...

  5. scala学习遇到的坑

    1:软件是idea,在同一个包中,类名一样,会导致在调用类的时候,程序无法找到正确的类,最后出错. 2:return坑,在方法中,返回值的类型已经指定了,所以可以放心使用return,但是在函数中,没 ...

  6. Array : 数组的常用方法

    数组常用方法 对象通用方法 1.toLocalString()  数组中的每个元素都会调用toLocalString(),然后以逗号隔开, 拼接为字符串: 2.toString() 数组中的每个元素都 ...

  7. PB 点击标题行排序和双击打开编辑页面共存不冲突的方法

    根据doubleclicked() 事件的参数 row 进行判断 大于0才进入编辑页面(不能用getrow()事件获取行id,双击标题行获取的是1) if row>0 then event ue ...

  8. 【题解】Luogu P5283 [十二省联考2019]异或粽子

    原题传送门 看见一段的异或和不难想到要做异或前缀和\(s\) 我们便将问题转化成:给定\(n\)个数,求异或值最靠前的\(k\)对之和 我们珂以建一个可持久化01trie,这样我们就珂以求出每个值\( ...

  9. kafka学习笔记(二)——基础入门

    1.集群规划 从官网下载jar包 http://kafka.apache.org/downloads.html,我选择的是kafka_2.11-0.11.0.0.tgz版本 规划一下集群环境先~ ha ...

  10. Django:缓存及相关配置

    缓存 由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache ...