Problem:
H - Rings
Problem Statement
There are two circles with radius 1 in 3D space. Please check two circles are connected as chained rings.
Input
The input is formatted as follows.
{c_x}_1
{c_y}_1
{c_z}_1
{v_x}_{1,1}
{v_y}_{1,1}
{v_z}_{1,1}
{v_x}_{1,2}
{v_y}_{1,2}
{v_z}_{1,2}
{c_x}_2
{c_y}_2
{c_z}_2
{v_x}_{2,1}
{v_y}_{2,1}
{v_z}_{2,1}
{v_x}_{2,2}
{v_y}_{2,2}
{v_z}_{2,2}
First line contains three real numbers(
-3 \leq {c_x}_i, {c_y}_i, {c_z}_i \leq 3
).
It shows a circle's center position.
Second line contains six real numbers(
-1 \leq {v_x}_{i,j}, {v_y}_{i,j}, {v_z}_{i,j} \leq 1
).
A unit vector (
{v_x}_{1,1}, {v_y}_{1,1}, {v_z}_{1,1}
) is directed to the circumference of the circle from center of the circle.
The other unit vector (
{v_x}_{1,2}, {v_y}_{1,2}, {v_z}_{1,2}
) is also directed to the circumference of the circle from center of the circle.
These two vectors are orthogonalized.
Third and fourth lines show the other circle information in the same way of first and second lines.
There are no cases that two circles touch.
Output
If two circles are connected as chained rings, you should print "YES". The other case, you should print "NO". (quotes for clarity)
Sample Input 1
0.0 0.0 0.0
1.0 0.0 0.0 0.0 1.0 0.0
1.0 0.0 0.5
1.0 0.0 0.0 0.0 0.0 1.0
Output for the Sample Input 1
YES
Sample Input 2
0.0 0.0 0.0
1.0 0.0 0.0 0.0 1.0 0.0
0.0 3.0 0.0
0.0 1.0 0.0 -1.0 0.0 0.0
Output for the Sample Input 2
NO
Sample Input 3
1.2 2.3 -0.5
1.0 0.0 0.0 0.0 1.0 0.0
1.1 2.3 -0.4
1.0 0.0 0.0 0.0 0.70710678 0.70710678
Output for the Sample Input 3
YES
Sample Input 4
1.2 2.3 -0.5
1.0 0.0 0.0 0.0 1.0 0.0
1.1 2.7 -0.1
1.0 0.0 0.0 0.0 0.70710678 0.70710678
Output for the Sample Input 4
NO

Submitted solutions:

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;

const double eps = 1e-5;
int sgn(double a){return a<-eps?-1:a>eps?1:0;}
struct point{
    double x,y,z;
    point() {}
    point(double x,double y,double z): x(x),y(y),z(z) {}
    point operator+ (const point& p){
        return point(x+p.x,y+p.y,z+p.z);
    }
    point operator- (const point& p){
        return point(x-p.x,y-p.y,z-p.z);
    }
    point operator* (const double d){
        return point(x*d,y*d,z*d);
    }
};

void YES(){
    cout << "YES" << endl; exit(0);
}
void NO(){
    cout << "NO" << endl; exit(0);
}

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    vector<point> p(6);
    for(int i=0;i<6;i++){
        cin >> p[i].x >> p[i].y >> p[i].z;
    }
    for(int i=0;i<6;i++){
        if(i%3) p[i] = p[i]+p[i/3*3];
    }
    // 1つ目の円の中心を原点へ平行移動
    for(int i=5;i>=0;i--){
        p[i] = p[i]-p[0];
    }
    // z軸中心に回転し、p[1]をxz平面上へ
    {
        double theta = -atan2(p[1].y, p[1].x);
        for(int i=0;i<6;i++){
            double nx = p[i].x*cos(theta) - p[i].y*sin(theta);
            double ny = p[i].x*sin(theta) + p[i].y*cos(theta);
            p[i].x = nx, p[i].y = ny;
        }
    }
    // y軸中心に回転し、p[1]をx軸上へ
    {
        double theta = -atan2(p[1].z, p[1].x);
        for(int i=0;i<6;i++){
            double nx = p[i].x*cos(theta) - p[i].z*sin(theta);
            double nz = p[i].x*sin(theta) + p[i].z*cos(theta);
            p[i].x = nx, p[i].z = nz;
        }
    }
    // x軸中心に回転し、p[2]をy軸上へ
    {
        double theta = -atan2(p[2].z, p[2].y);
        for(int i=0;i<6;i++){
            double ny = p[i].y*cos(theta) - p[i].z*sin(theta);
            double nz = p[i].y*sin(theta) + p[i].z*cos(theta);
            p[i].y = ny, p[i].z = nz;
        }
    }
    // 2つ目の円の中心がxy平面上にあったらNO
    if(!sgn(p[3].z)) NO();

    // ちょっとずるい方法で2つ目の円とxy平面上の交点を求める
    // 2piを適当に刻んでそれぞれの座標を見る
    double pi = acos(-1);
    vector<point> v(2);
    v[0] = p[4]-p[3];
    v[1] = p[5]-p[3];
    vector<double> d;
    const int N = 1000000;
    for(int i=0;i<N;i++){
        double theta = 2.0*pi/N*i;
        point P = p[3]+v[0]*cos(theta)+v[1]*sin(theta);
        if(!sgn(P.z)){
            double dist = sqrt(P.x*P.x + P.y*P.y);
            d.push_back(dist);
        }
    }
    sort(d.begin(), d.end());
    int bit = 0;
    for(auto dd:d){
        int s = sgn(abs(dd)-1);
        if(s > 0) bit |= 1;
        else if(s < 0) bit |= 2;
    }
    if(bit == 3) YES();
    else NO();
}
accuracy: 1
time_ms: 10
memory_kb: 4032
final_rank: 2

code_snippet: #pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;

const double eps = 1e-5;
int sgn(double a){return a<-eps?-1:a>eps?1:0;}
struct point{
    double x,y,z;
    point() {}
    point(double x,double y,double z): x(x),y(y),z(z) {}
    point operator+ (const point& p){
        return point(x+p.x,y+p.y,z+p.z);
    }
    point operator- (const point& p){
        return point(x-p.x,y-p.y,z-p.z);
    }
    point operator* (const double d){
        return point(x*d,y*d,z*d);
    }
};

void YES(){
    cout << "YES" << endl; exit(0);
}
void NO(){
    cout << "NO" << endl; exit(0);
}

int main(){
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    vector<point> p(6);
    for(int i=0;i<6;i++){
        cin >> p[i].x >> p[i].y >> p[i].z;
    }
    for(int i=0;i<6;i++){
        if(i%3) p[i] = p[i]+p[i/3*3];
    }
    // 1つ目の円の中心を原点へ平行移動
    for(int i=5;i>=0;i--){
        p[i] = p[i]-p[0];
    }
    // z軸中心に回転し、p[1]をxz平面上へ
    {
        double theta = -atan2(p[1].y, p[1].x);
        for(int i=0;i<6;i++){
            double nx = p[i].x*cos(theta) - p[i].y*sin(theta);
            double ny = p[i].x*sin(theta) + p[i].y*cos(theta);
            p[i].x = nx, p[i].y = ny;
        }
    }
    // y軸中心に回転し、p[1]をx軸上へ
    {
        double theta = -atan2(p[1].z, p[1].x);
        for(int i=0;i<6;i++){
            double nx = p[i].x*cos(theta) - p[i].z*sin(theta);
            double nz = p[i].x*sin(theta) + p[i].z*cos(theta);
            p[i].x = nx, p[i].z = nz;
        }
    }
    // x軸中心に回転し、p[2]をy軸上へ
    {
        double theta = -atan2(p[2].z, p[2].y);
        for(int i=0;i<6;i++){
            double ny = p[i].y*cos(theta) - p[i].z*sin(theta);
            double nz = p[i].y*sin(theta) + p[i].z*cos(theta);
            p[i].y = ny, p[i].z = nz;
        }
    }
    // 2つ目の円の中心がxy平面上にあったらNO
    if(!sgn(p[3].z)) NO();

    // ちょっとずるい方法で2つ目の円とxy平面上の交点を求める
    // 2piを適当に刻んでそれぞれの座標を見る
    double pi = acos(-1);
    vector<point> v(2);
    v[0] = p[4]-p[3];
    v[1] = p[5]-p[3];
    vector<double> d;
    const int N = 1000000;
    for(int i=0;i<N;i++){
        double theta = 2.0*pi/N*i;
        point P = p[3]+v[0]*cos(theta)+v[1]*sin(theta);
        if(!sgn(P.z)){
            double dist = sqrt(P.x*P.x + P.y*P.y);
            // cout << P.x << " " << P.y << " " << P.z << endl; 
            bool ok = true;
            for(auto dd:d){
                if(!sgn(dist-dd)) ok = false;
            }
            if(ok) d.push_back(dist);
        }
    }
    sort(d.begin(), d.end());
    if(d.size() == 2 and sgn(abs(d[0])-1) < 0 and sgn(abs(d[1])-1) > 0) YES();
    else NO();
}
accuracy: 0.10666666666666667
time_ms: 10
memory_kb: 4028
final_rank: 4

code_snippet: #include <cmath>
#include <iostream>
using namespace std;
const int spl = 1048576;
const double pi = acos(-1.0);
class point3d {
public:
	double x, y, z;
	point3d() : x(0), y(0), z(0) {};
	point3d(double x_, double y_, double z_) : x(x_), y(y_), z(z_) {};
	point3d& operator+=(const point3d& p) { x += p.x; y += p.y; z += p.z; return *this; }
	point3d& operator-=(const point3d& p) { x -= p.x; y -= p.y; z -= p.z; return *this; }
	point3d& operator*=(const double v) { x *= v; y *= v, z *= v; return *this; }
	point3d operator+(const point3d& p) const { return point3d(*this) += p; }
	point3d operator-(const point3d& p) const { return point3d(*this) -= p; }
	point3d operator*(const double v) const { return point3d(*this) *= v; }
	double abs() const { return sqrt(x * x + y * y + z * z); }
	double dot(point3d& p) const { return x * p.x + y * p.y + z * p.z; }
	point3d cross(point3d& p) const { return point3d(y * p.z - z * p.y, z * p.x - x * p.z, x * p.y - y * p.x); }
};
void input(point3d *v) {
	cin >> (*v).x >> (*v).y >> (*v).z;
}
int main() {
	point3d c1, vx1, vy1, c2, vx2, vy2;
	input(&c1); input(&vx1); input(&vy1); input(&c2); input(&vx2); input(&vy2);
	point3d vz2 = vx2.cross(vy2);
	bool flag = false;
	int cnt = 0;
	double pre = -1.0;
	for (int i = 0; i <= spl; ++i) {
		double ang = i * 2 * pi / spl;
		point3d p = c1 + vx1 * cos(ang) + vy1 * sin(ang);
		point3d d = p - c2;
		double t = d.dot(vz2);
		if (i >= 1 && d.abs() <= 1.0 && pre * t <= 0.0) {
			++cnt;
		}
		pre = t;
	}
	cout << (cnt == 1 ? "YES\n" : "NO\n");
	return 0;
}
accuracy: 1
time_ms: 50
memory_kb: 3624
final_rank: 3

code_snippet: #include <cmath>
#include <iostream>
using namespace std;
const int spl = 1048576;
const double pi = acos(-1.0);
class point3d {
public:
	double x, y, z;
	point3d() : x(0), y(0), z(0) {};
	point3d(double x_, double y_, double z_) : x(x_), y(y_), z(z_) {};
	point3d& operator+=(const point3d& p) { x += p.x; y += p.y; z += p.z; return *this; }
	point3d& operator-=(const point3d& p) { x -= p.x; y -= p.y; z -= p.z; return *this; }
	point3d& operator*=(const double v) { x *= v; y *= v, z *= v; return *this; }
	point3d& operator+(const point3d& p) const { return point3d(*this) += p; }
	point3d& operator-(const point3d& p) const { return point3d(*this) -= p; }
	point3d& operator*(const double v) const { return point3d(*this) *= v; }
	double abs() const { return sqrt(x * x + y * y + z * z); }
	double dot(point3d& p) const { return x * p.x + y * p.y + z * p.z; }
	point3d cross(point3d& p) const { return point3d(y * p.z - z * p.y, z * p.x - x * p.z, x * p.y - y * p.x); }
};
void input(point3d *v) {
	cin >> (*v).x >> (*v).y >> (*v).z;
}
int main() {
	point3d c1, vx1, vy1, c2, vx2, vy2;
	input(&c1); input(&vx1); input(&vy1); input(&c2); input(&vx2); input(&vy2);
	point3d vz2 = vx2.cross(vy2);
	bool flag = false;
	for (int i = 0; i < spl; ++i) {
		double ang = i * 2 * pi / spl;
		point3d p = c1 + (vx1 * sin(ang) + vy1 * cos(ang));
		if ((p - c2).abs() <= 1.0 && (p - c2).dot(vz2) <= pi / spl) {
			flag = true;
		}
	}
	cout << (flag ? "YES\n" : "NO\n");
	return 0;
}
accuracy: 0.013333333333333334
time_ms: 40
memory_kb: 3136
final_rank: 5

code_snippet: #include<stdio.h>
#include<algorithm>
#include<math.h>
using namespace std;
double PI=acos(-1.0);
double EPS=1e-9;
double ABS(double a){return max(a,-a);}
int main(){
	double acx,acy,acz,bcx,bcy,bcz;
	double avx1,avx2,avy1,avy2,avz1,avz2;
	double bvx1,bvx2,bvy1,bvy2,bvz1,bvz2;
	scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf",&acx,&acy,&acz,&avx1,&avy1,&avz1,&avx2,&avy2,&avz2);
	scanf("%lf%lf%lf%lf%lf%lf%lf%lf%lf",&bcx,&bcy,&bcz,&bvx1,&bvy1,&bvz1,&bvx2,&bvy2,&bvz2);
	int cnt=0;
	double wx=avy1*avz2-avz1*avy2;
	double wy=avz1*avx2-avx1*avz2;
	double wz=avx1*avy2-avy1*avx2;
//	printf("%f %f %f\n",wx,wy,wz);
	for(int i=0;i<10000;i++){
		double X1=bcx+bvx1*sin(PI*2/10000*i)+bvx2*cos(PI*2/10000*i);
		double Y1=bcy+bvy1*sin(PI*2/10000*i)+bvy2*cos(PI*2/10000*i);
		double Z1=bcz+bvz1*sin(PI*2/10000*i)+bvz2*cos(PI*2/10000*i);
		double X2=bcx+bvx1*sin(PI*2/10000*(i+1))+bvx2*cos(PI*2/10000*(i+1));
		double Y2=bcy+bvy1*sin(PI*2/10000*(i+1))+bvy2*cos(PI*2/10000*(i+1));
		double Z2=bcz+bvz1*sin(PI*2/10000*(i+1))+bvz2*cos(PI*2/10000*(i+1));
		double L=0;
		double R=1;
		double dist=999999999;
		for(int j=0;j<100;j++){
			double m1=(L*2+R)/3;
			double m2=(L+R*2)/3;
			double px=X1*m1+X2*(1.0-m1)-acx;
			double py=Y1*m1+Y2*(1.0-m1)-acy;
			double pz=Z1*m1+Z2*(1.0-m1)-acz;
			double qx=X1*m2+X2*(1.0-m2)-acx;
			double qy=Y1*m2+Y2*(1.0-m2)-acy;
			double qz=Z1*m2+Z2*(1.0-m2)-acz;
			double D1=ABS(px*wx+py*wy+pz*wz);
			double D2=ABS(qx*wx+qy*wy+qz*wz);
			dist=min(dist,min(D1,D2));
			if(D1<D2){
				R=m2;
			}else{
				L=m1;
			}
		}
	//	printf("%d: %f\n",i,dist);
		if(dist>EPS)continue;
		double x=X1*L+X2*(1.0-L)-acx;
		double y=Y1*L+Y2*(1.0-L)-acy;
		double z=Z1*L+Z2*(1.0-L)-acz;
		if(x*x+y*y+z*z<1.0)cnt++;
	}
	if(cnt==1)printf("YES\n");
	else printf("NO\n");
}
accuracy: 1
time_ms: 40
memory_kb: 1048
final_rank: 1