問題はこちら
No.55 正方形を描くだけの簡単なお仕事です。 - yukicoder
もし正方形になり得る3点なら
その3点は直角二等辺三角形になっているはず
なので、「その点の周りが直角で、それをなす辺の長さが等しい」というような点が3つの中にあるかどうか探す
main(){ int x[6],i,a,b,c,d,f=0; for(i=0;i<6;i++)scanf("%d",x+i); for(i=4;i>=0;i-=2){ //(x[0],x[1])まわりが直角かどうかを調べる a=x[2]-*x;b=x[3]-x[1]; c=x[4]-*x;d=x[5]-x[1]; //辺の長さ if(a*c+b*d==0&a*a+b*b==c*c+d*d){f=1;break;} //内積が0(⇔直角)かつ辺の長さが等しいならフラグを立てて脱出 *x^=x[i]^=*x^=x[i]; x[1]^=x[i+1]^=x[1]^=x[i+1]; //点の入れ替え(後述) } if(f)printf("%d %d",x[2]+x[4]-*x,x[3]+x[5]-x[1]) //正方形が書けるなら座標の出力(後述) else printf("-1"); //無理なら-1 return 0; }
点の入れ替えについて
常に(x[0],x[1])周りを調べることにしているので、全ての点について調べるには座標の方を入れ替える必要がある
最初に読み込んだ時を(a,b)(c,d)(e,f)とすると
1回目…(a,b)(c,d)(e,f)
2回目…(c,d)(a,b)(e,f)
3回目…(e,f)(a,b)(c,d)
と、ちゃんと全ての点について調べられている
座標の出力について
最後の1点を(p,q)とすると、完成する正方形の対角線の中心は
((x[2]+x[4])/2,(x[3]+x[5])/2)=((x[0]+p)/2,(x[1]+q)/2)
となるのでこれを解けば上の式が得られる
xorswapを2回も書くと長いよね…
ということで1回にした
x[6],i,a,b,c; main(d){ for(;~scanf("%d",x+i);i++); for(;i;){ a=x[2]-*x;b=x[3]-x[1]; c=x[4]-*x;d=x[5]-x[1]; if(i%2==0&&a*c+b*d==0&&a*a+b*b==c*c+d*d)break; i--; //x[i%2]^=x[i]^=x[i%2]^=x[i];←yukicoderの環境だとバグる a=x[i%2];x[i%2]=x[i];x[i]=a; } i?printf("%d %d",x[2]+c,x[3]+d):puts("-1"); return 0; }
2つのベクトル(a,b)と(c,d)が90度で交わり大きさが等しいことの判定はもっと簡単にできる
だって結局(c,d)は(-b,a)か(b,-a)になるしかない
x[6],i,a,b,c; main(d){ for(;~scanf("%d",x+i);i++); for(;a=x[2]-*x,b=x[3]-x[1],c=x[4]-*x,d=x[5]-x[1],i&&i--%2|(a+d|b-c&&a-d|b+c);x[i]^=x[i%2]^=x[i]^=x[i%2]); //今度はxorswapでもバグらない i=!printf(i?"%d %d":"-1",x[2]+c,x[3]+d); }
代入文を押し込むことで
for(;~scanf("%d",x+i);i++);for(;a=x[2]-*x,b=x[3]-x[1],c=x[4]-*x,d=x[5]-x[1],i&&i--%2|(a+d|b-c&&a-d|b+c);x[i]^=x[i%2]^=x[i]^=x[i%2]); //↑before ↓after for(;~scanf("%d",x+i)?++i:i&&i--%2|((a=x[2]-*x)+(d=x[5]-x[1])|(b=x[3]-x[1])-(c=x[4]-*x)&&a-d|b+c)?x[i]^=x[i%2]^=x[i]^=x[i%2],1:0;);
とループ圧縮でき、最後の出力もループ内に押しこむことが出来て
x[6],i,a,b,c;main(d){ for(;a=~scanf("%d",x+i)?++i:i&&i--%2|((a=x[2]-*x)+(d=x[5]-x[1])|(b=x[3]-x[1])-(c=x[4]-*x)&&a-d|b+c)?x[i]^=x[i%2]^=x[i]^=x[i%2],1:!printf(i?"%d %d":"-1",x[2]+c,x[3]+d);); }
191B