【BZOJ】3621 我想那还真是令人高兴啊-复数

传送门:bzoj3621


题解

我们把每个坐标看成一个复数,在复平面上两两之间连线的变换值恰好可以用同一个复数表示(这里讲的不清晰,还是贴一下PoPoQQQ的题解)

首先两个复数相乘的几何意义是【极角相加,长度相乘】 这两种变换正好对应旋转和放缩
那么我们不妨将所有点都放到复平面上
由于没有给定点的对应关系,故我们3!枚举这个对应关系
设其中一个三角形的三个顶点为A,B,C,另一个三角形中对应顶点为A',B',C'
设中心点为P,变换复数为T
那么我们有方程组:
(A-P)T=(A'-P)
(B-P)T=(B'-P)
(C-P)T=(C'-P)
由前两个方程解得
T=(A'-B')/(A-B)
P=(AT-A')/(T-1)

代入第三个方程中验证即可。

代码

#include<bits/stdc++.h>
#define db double
using namespace std;
const db pi=acos(-1);
const db eps=1e-4;

int T;

struct Complex{db real,imag;}a,b,c,p[4];
typedef Complex cc;
cc operator *(cc x,cc y)
{return (cc){x.real*y.real-x.imag*y.imag,x.real*y.imag+x.imag*y.real};}
cc operator +(cc x,cc y)
{return (cc){x.real+y.real,x.imag+y.imag};}
cc operator -(cc x,cc y)
{return (cc){x.real-y.real,x.imag-y.imag};}
cc operator /(cc x,cc y){
    db wel=y.imag*y.imag+y.real*y.real;
    return (cc){(x.real*y.real+x.imag*y.imag)/wel,(x.imag*y.real-x.real*y.imag)/wel};
}
bool operator ==(cc x,cc y)
{return (fabs(x.real-y.real)<eps) && (fabs(x.imag-y.imag)<eps);}

db xa,ya;
bool ptr;

inline void dfs(cc A,cc B,cc C)
{
    if(ptr) return;
    cc T=(A-B)/(a-b);cc P=(a*T-A)/(T-(cc){1,0});
    if((c-P)*T==(C-P)){
      ptr=true;
      printf("%.6lf %.6lf\n",P.real,P.imag);
      return;
    }
}

int main(){
    scanf("%d",&T);
    while(T--){
        ptr=false;
        scanf("%lf%lf%lf%lf%lf%lf",&a.real,&a.imag,&b.real,&b.imag,&c.real,&c.imag);
        scanf("%lf%lf%lf%lf%lf%lf",&p[0].real,&p[0].imag,&p[1].real,&p[1].imag,&p[2].real,&p[2].imag);
        dfs(p[0],p[1],p[2]);dfs(p[0],p[2],p[1]);dfs(p[1],p[2],p[0]);
        dfs(p[1],p[0],p[2]);dfs(p[2],p[1],p[0]);dfs(p[2],p[0],p[1]);
    }
    return 0;
}

ps:然而事实证明了eps必须开到1e-4,小了就会WA…

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/80349504
今日推荐