【题目背景】
这是一道传统题 .......。
Endless Endless 一觉醒来,发现自己的电脑中了病毒。
桌面上 的文件全部离奇地消失了,只剩下 的文件全部离奇地消失了,只剩下 三个不相交的矩形,并且有一行 三个不相交的矩形,并且有一行 字:
“那个成功画出最完美的直角三形人才是这台电脑真正主。 ”
Endless Endless 知道自己的行踪被发现了。他想立刻揪出这个在电脑中散布病 知道自己的行踪被发现了。但是他 用尽了办法竟然解不开被锁定的电脑。求助于你 ,要 如何 画出这个 “完美的直角三形 ”。
【题目描述】
你得到了三个不相交的矩形。
由于你是在平面直角坐标系上,这三个矩形可以用4个正实数 x1, y1, x2, y2表示。其中(x1, y1)是矩形的左下角,(x2, y2)是矩形的右上角。
你需要判断从这三个矩形中各取出一个点是否能组成一个直角三角形。
如果能的话,请输出任意一种方案。
【输入格式】
从文件 rigtri.in 中读入数据。
本题单个测试点中包含多组数据。
输入的第一行为数据组数T。
接下来T行,每行12个[0,109]内的实数,分别表示三个矩形的左下角坐标和右上角坐标。保证矩形互不相交。
【输出格式】
输出到 rigtri.out 中。
输出 T行,每行对应一组数据的答案 。
如果第 i组数据 有解,第 i行输出 6个非负 实数 x1, y1, x2, y2, x3, y3,表示第 i行的答案,其中 (x1, y1)应该落在矩形 1内,其他 2个点同理。
否则请在这一行输出 -1。
你的输出将经过 Special JudgeSpecial Judge Special JudgeSpecial Judge Special Judge Special Judge的检验。
如果你的每个回答都是合法,且三点构成了一直角 形(两条如果你的每个回答都是合法,且三点构成了一直角 形(两条如果你的每个回答都是合法,且三点构成了一直角 形(两条边的 长度平方和与斜绝对 ..误差或 ...相对误差 ....不超过 10-3), 那么你得到这个测试点的满分( 5分);否则,如果你正确地判断了 所有的 ...无解情况,你得到这个测试点的 40%分数( 2分)。
注意:请不要在应该输出 -1的时候输出 负数 ..,否则会 得到 Format ErrorFormat Error Format Error Format Error Format Error , 该测试点计 0分。
【样例1输入】
2
0 0 1 1 5 0 6 1 9 0 10 1
0 0 1 1 4 1 5 2 3 5 4 6
【样例1输出】
-1
1 1 4 1 4 5
【样例1解释】
例如以下的答案也将得到正确。
-1
0.4720906 0.4590820 4.5539210 1.3531973 3.6576131 5.4450373
首先,作为一道毒瘤几何题。必定有特殊性质。
一、若存在合法三角形,必有一解,使得三点在三个矩形的边上。
二、若存在合法三角形,必有一解,使得两点在矩形顶点上
证明略。
所以可以枚举两个顶点构成一条边,判断。
一、该边为斜边,可以解圆方程
二、该边为直角边,可以用直线解析式解。
注意:判断大小时要加上精度,且对于与x轴和y轴平行的线不能用解析式,否则
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<stdio.h>
#include<iostream>
#include<cmath>
#include<assert.h>
using namespace std;
#define EPS (1e-10)
#define equals(a, b) (fabs((a) - (b)) < EPS)
const double eps=1e-4;
class Point {//Point类,点
public:
double x, y;
Point(double x = 0, double y = 0): x(x), y(y) {}
Point operator + (Point p) { return Point(x + p.x, y + p.y); }
Point operator - (Point p) { return Point(x - p.x, y - p.y); }
Point operator * (double a) { return Point(a * x, a * y); }
Point operator / (double a) { return Point(x / a, y / a); }
double abs() { return sqrt(norm()); }
double norm() { return x * x + y * y; }
bool operator < (const Point &p) const {
return x != p.x ? x < p.x : y < p.y;
}
bool operator == (const Point &p) const {
return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
}
};
typedef Point Vector;//Vector类,向量
struct Segment{//Segment 线段
Point p1, p2;
};
typedef Segment Line;
class Circle {//Circle 圆
public:
Point c;
double r;
Circle(Point c = Point(), double r = 0.0): c(c), r(r) {}
};
double dot(Vector a, Vector b) {//内积
return a.x * b.x + a.y * b.y;
}
double cross(Vector a, Vector b) {//外积
return a.x*b.y - a.y*b.x;
}
Point project(Segment s, Point p) {//投影 对于给定的三个点p1、p2、p,从点p向通过
//p1、p2的直线引一条垂线,求垂足x的坐标。(点p在直线p1p2上的投影)
Vector base = s.p2 - s.p1;
double r = dot(p - s.p1, base) / base.norm();
return s.p1 + base * r;
}
double getDistanceLP(Line l, Point p) {//直线l和点p的距离
return abs(cross(l.p2 - l.p1, p - l.p1) / (l.p2 - l.p1).abs() );
}
bool intersect(Circle c, Line l) {
if(getDistanceLP(l, c.c) > c.r) {
return false;
} else {
return true;
}
}
Point getCrossPoint(Segment s1, Segment s2) {
Vector base = s2.p2 - s2.p1;
double d1 = abs(cross(base, s1.p1 - s2.p1));
double d2 = abs(cross(base, s1.p2 - s2.p1));
double t = d1 / (d1 + d2);
return s1.p1 + (s1.p2 - s1.p1) * t;
}
pair<Point, Point> getCrossPoints(Circle c, Line l) {
assert(intersect(c, l));
Vector pr = project(l, c.c);
Vector e = (l.p2 - l.p1) / (l.p2 - l.p1).abs();
double base = sqrt(c.r * c.r - (pr - c.c).norm() );
return make_pair(pr + e * base, pr - e * base);
}
inline double get_dis(double X1,double Y1,double X2,double Y2,double X0,double Y0){
double res,a,b,c;//以双精度保存变量
// cin>>x1>>y1>>x2>>y2>>x0>>y0;//输入三组数据
a=(X0-X1)*(Y2-Y1);//分子的左半部分
b=(Y0-Y1)*(X1-X2);//分子的右半部分
c=a+b;//二者相加
c*=c;//平方(pow(c,2)貌似在这里更加麻烦)
a=pow(Y2-Y1,2);//分母左半部分
b=pow(X1-X2,2);//分母右半部分
c/=(a+b);//分子分母相除
res=sqrt(c);//开方
// printf("%.6lf",res);//输出
return res;
}
struct node{
double x[4],y[4];
}ma[3];
int flag=0;int t;
double ans_x[3],ans_y[3];
double final_x[3],final_y[3];
Circle dfs_c;double c_x,c_y;
pair<double, double> get_line(double x,double y,double xx,double yy){
double b=(yy*x-y*xx)/(x-xx);
if(x==xx)return make_pair(0,0);
return make_pair((yy-y)/(xx-x),b);
}void test(int kong){
final_x[0]=ans_x[0];final_y[0]=ans_y[0];final_x[1]=ans_x[1];final_y[1]=ans_y[1];final_x[2]=ans_x[2];final_y[2]=ans_y[2];
}
void pd_x(int kong){
Line l;
l.p1.x=(dfs_c.c.x+c_x)/2;l.p1.y=(dfs_c.c.y+c_y)/2;
l.p2.x=dfs_c.c.x-l.p1.x;l.p2.y=dfs_c.c.y-l.p1.y;
pair<double, double> pre=get_line(l.p1.x,l.p1.y,l.p2.x,l.p2.y),suf;
double k=-1/pre.first,b;double x,y;
for(int i=0;i<4;++i){
if(l.p1.x==l.p2.x){
if(min(ma[kong].y[i],ma[kong].y[(i+1)%4])<=l.p1.y&&max(ma[kong].y[i],ma[kong].y[(i+1)%4])>=l.p1.y){
flag=1;ans_x[kong]=ma[kong].x[i];ans_y[kong]=l.p1.y;
break;
}
if(min(ma[kong].y[i],ma[kong].y[(i+1)%4])<=l.p2.y&&max(ma[kong].y[i],ma[kong].y[(i+1)%4])>=l.p2.y){
flag=1;ans_x[kong]=ma[kong].x[i];ans_y[kong]=l.p2.y;
break;
}
continue;
}
b=l.p1.y-k*l.p1.x;
if(i&1){x=ma[kong].x[i],y=x*k+b;}
else{y=ma[kong].y[i],x=(y-b)/k;}
if(x>=min(ma[kong].x[i],ma[kong].x[(i+1)%4])-eps&&x<=max(ma[kong].x[i],ma[kong].x[(i+1)%4])+eps&&y>=min(ma[kong].y[i],ma[kong].y[(i+1)%4])-eps&&y<=max(ma[kong].y[i],ma[kong].y[(i+1)%4])+eps){
flag=1;ans_x[kong]=x;ans_y[kong]=y;
test(kong);
}
b=l.p2.y-k*l.p2.x;
if(i&1){x=ma[kong].x[i],y=x*k+b;}
else{y=ma[kong].y[i],x=(y-b)/k;}
if(x>=min(ma[kong].x[i],ma[kong].x[(i+1)%4])-eps&&x<=max(ma[kong].x[i],ma[kong].x[(i+1)%4])+eps&&y>=min(ma[kong].y[i],ma[kong].y[(i+1)%4])-eps&&y<=max(ma[kong].y[i],ma[kong].y[(i+1)%4])+eps){
flag=1;ans_x[kong]=x;ans_y[kong]=y;
test(kong);
}
if(flag)break;
}
}void pd_yuan(int kong){
Circle c=dfs_c;
Line l;
c.c.x/=2;c.c.y/=2;
c.r=sqrt(c_x*c_x+c_y*c_y)/2;
pair<Point, Point> p;
for(int i=0;i<4;++i){
if(flag)break;
l.p1.x=ma[kong].x[i],l.p1.y=ma[kong].y[i];l.p2.x=ma[kong].x[(i+1)%4],l.p2.y=ma[kong].y[(i+1)%4];
double len=get_dis(l.p1.x,l.p1.y,l.p2.x,l.p2.y,c.c.x,c.c.y);
if(len>c.r)continue;
p = getCrossPoints(c, l);
double x=p.first.x,y=p.first.y;
if(x>=min(ma[kong].x[i],ma[kong].x[(i+1)%4])-eps&&x<=max(ma[kong].x[i],ma[kong].x[(i+1)%4])+eps&&y>=min(ma[kong].y[i],ma[kong].y[(i+1)%4])-eps&&y<=max(ma[kong].y[i],ma[kong].y[(i+1)%4])+eps){
flag=1;ans_x[kong]=x;ans_y[kong]=y;
test(kong);
}
x=p.second.x;y=p.second.y;
if(x>=min(ma[kong].x[i],ma[kong].x[(i+1)%4])-eps&&x<=max(ma[kong].x[i],ma[kong].x[(i+1)%4])+eps&&y>=min(ma[kong].y[i],ma[kong].y[(i+1)%4])-eps&&y<=max(ma[kong].y[i],ma[kong].y[(i+1)%4])+eps){
flag=1;ans_x[kong]=x;ans_y[kong]=y;
test(kong);
}
}
inline void prin(){
printf("%.12lf %.12lf %.12lf %.12lf %.12lf %.12lf\n",final_x[0],final_y[0],final_x[1],final_y[1],final_x[2],final_y[2]);
}
int xuan[3];
void dfs(int x,int cnt,int kong){
if(cnt>2)return ;
if(flag)return ;
if(x>2&&cnt<2)return ;
if(x>2){
pd_x(kong);
dfs_c.r=sqrt(c_x*c_x+c_y*c_y)/2;
if(flag)return;
pd_yuan(kong);
return ;
}
dfs(x+1,cnt,x);
for(int i=0;i<4;++i){
dfs_c.c.x+=ma[x].x[i];
dfs_c.c.y+=ma[x].y[i];
c_x+=cnt==0?ma[x].x[i]:-ma[x].x[i];
c_y+=cnt==0?ma[x].y[i]:-ma[x].y[i];
ans_x[x]=ma[x].x[i];ans_y[x]=ma[x].y[i];
xuan[x]=i;
dfs(x+1,cnt+1,kong);
xuan[x]=-1;
dfs_c.c.x-=ma[x].x[i];
dfs_c.c.y-=ma[x].y[i];
c_x-=cnt==0?ma[x].x[i]:-ma[x].x[i];
c_y-=cnt==0?ma[x].y[i]:-ma[x].y[i];
if(flag)return ;
}
}
int main(){
int t;cin>>t;int k;cin>>k;
xuan[0]=xuan[1]=xuan[2]=-1;
while(t--){
dfs_c.c.x=dfs_c.c.y=dfs_c.r=0;c_x=c_y=0;
for(int i=0;i<3;++i){
scanf("%lf%lf%lf%lf",&ma[i].x[0],&ma[i].y[0],&ma[i].x[2],&ma[i].y[2]);
ma[i].x[1]=ma[i].x[2];ma[i].y[1]=ma[i].y[0];
ma[i].x[3]=ma[i].x[0];ma[i].y[3]=ma[i].y[2];
}
flag=0;
dfs(0,0,-1);
if(flag){
printf("%.12lf %.12lf %.12lf %.12lf %.12lf %.12lf\n",final_x[0],final_y[0],final_x[1],final_y[1],final_x[2],final_y[2]);
}else cout<<"-1"<<endl;
}
return 0;
}