上链接:Problem - 7205
相当奇怪的解决方法,可能是一些常规解法的衍生品,比较容易理解。
分析
直接上分析内容(本来做好PDF版的题解但是好像发不上来)
考虑两个矩形对应边平行的情况
易知所求点位于两个矩形的重心连线所在直线上,位置与缩放比有关。
考虑两个矩形对应边不平行的情况
令AB与ab交于E,CD与cd交于F,AD与ad交于G,BC与bc交于H,则P为EF与GH的交点。
图(1)
证明:
假定线段EF上的任一一点P满足以下性质:过P分别做大矩形长边与小矩形长边的垂线,大矩形上垂足所处位置与小矩形上所处位置比例一致(相对位置一致)。
即 PH⊥BC,PI⊥bc,则有BH/CH=bI/cI (1)
如图(2)所示
图(2)
若以上假设成立,对于图(1)中GH直线同样有类似性质,即线上的点到对应边的投影点满足在大小矩形的边上的相对位置一致。
因此对于直线EF与直线GH的交点P,满足了对于大小矩形长边上投影点的相对位置一致,也满足了在短边上投影点相对位置一致,即可确定该交点P即为所求点。
目前需要证明原假定成立,即(1)句成立。
现证一组成立即可,即证EF上点的性质。
取EF上任一点P,如图(2),在图(2)基础上过P点做两个矩形的长边的平行线,如图(3)。
图(3)
容易证明 bI=KP,cI=JP,MP=BH,LP=CH
有ΔEPK与ΔFPJ相似,则KP/JP=EP/PF
有ΔEPM与ΔFPL相似,则MP/PL=EP/FP
则KP/JP=MP/PL 故bI/cI=BH/CH
即原假设得证。
故原操作方法合理性得证。
奇怪的思路及其容易,很好理解。
其实就是巴纳赫不动点。可以自行了解。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double pi=acos(-1.0);
const double eps=1e-8;
int sgn(double x) {
if(fabs(x)<eps) return 0;
else return x<0?-1:1;
}
int Dcmp(double x,double y) {
if(fabs(x-y)<eps) return 0;
else return x<y?-1:1;
}
struct Point
{
double x,y;
Point() {}
Point(double x,double y):x(x),y(y) {}
Point operator +(Point B) {
return Point(x+B.x,y+B.y);
}
Point operator -(Point B) {
return Point(x-B.x,y-B.y);
}
Point operator *(double k) {
return Point(x*k,y*k);
}
Point operator /(double k) {
return Point(x/k,y/k);
}
};
typedef Point Vector;
double Cross(Vector A,Vector B) {
return A.x*B.y-A.y*B.x;
}
struct Line {
Point p1,p2;
Line() {}
Line(Point p1,Point p2):p1(p1),p2(p2) {}
};
Point Cross_point(Point a,Point b,Point c,Point d) {
double s1=Cross(b-a,c-a);
double s2=Cross(b-a,d-a);
return Point(c.x*s2-d.x*s1,c.y*s2-d.y*s1)/(s2-s1);
}
bool Line_px(Line v1,Line v2) {
if(sgn(Cross(v1.p2-v1.p1,v2.p2-v2.p1))==0) {
return 1;
} else {
return 0;
}
}
double Distance(Point A,Point B) {
return hypot(A.x-B.x,A.y-B.y);
}
void solve() {
Point A1,A2,A3,A4,B1,B2,B3,B4;
scanf("%lf%lf",&A1.x,&A1.y);
scanf("%lf%lf",&A2.x,&A2.y);
scanf("%lf%lf",&A3.x,&A3.y);
scanf("%lf%lf",&A4.x,&A4.y);
scanf("%lf%lf",&B1.x,&B1.y);
scanf("%lf%lf",&B2.x,&B2.y);
scanf("%lf%lf",&B3.x,&B3.y);
scanf("%lf%lf",&B4.x,&B4.y);
if(Line_px(Line(A1,A4),Line(B1,B4))) { //特判平行情况
//两个矩形的重心
Point m1((A1.x+A4.x)/2,(A1.y+A4.y)/2);
Point m2((B1.x+B4.x)/2,(B1.y+B4.y)/2);
if(Dcmp(m1.x,m2.x)==0&&Dcmp(m1.y,m2.y)==0) {
printf("%.6f %.6f\n",m1.x,m1.y);
} else {
double k=Distance(A1,A2)/Distance(B1,B2); //缩放比
double ansx=(k*m2.x-m1.x)/(k-1);
double ansy=(k*m2.y-m1.y)/(k-1);
printf("%.6f %.6f\n",ansx,ansy);
}
} else {
Point ans1=Cross_point(A1,A4,B1,B4);
Point ans2=Cross_point(A2,A3,B2,B3);
Point ans3=Cross_point(A1,A2,B1,B2);
Point ans4=Cross_point(A3,A4,B3,B4);
Point ans=Cross_point(ans1,ans2,ans3,ans4);
printf("%.6f %.6f\n",ans.x ,ans.y);
}
return;
}
int main() {
//freopen("t.in","r",stdin);
int t;scanf("%d",&t);
while(t--) solve();
}