■1212 Mirror Illusion
ある座標pから方向vを見ていたとする.ちなみに,初期条件は,p0=(0.75, 0.25),v0=(1, 1)vのノルムを16以上にとれば,(p+v)が必ず室外に出るので,以下vをそういうベクトルとする.
まず,(p, p+v)が人に当たるかを調べる.当たっていたらそこで終了.
次に,(p, p+v)が鏡に当たるかを調べる. 一つでも当たる鏡があれば,その内で交差点が最もpに近い鏡mを選ぶ.pを,(p, p+v)とmとの交差点とする.また,新しい方向ベクトルを, mが横置きだったらv'=(vx, -vy), 縦置きだったらv'=(-vx, vy)とする.
一つも当たらなかった場合は,外壁のいずれかに当たっていることになるので,4つの壁それぞれについて当たっているかおよび交差点を計算.
import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;
public class Main{
Scanner sc=new Scanner(System.in);
int INF=1<<28;
double EPS=1e-9;
int n;
int m;
Seg[] segs;
void run(){
m=8;
for(;;){
n=sc.nextInt();
if(n<0){
break;
}
segs=new Seg[n];
for(int i=0; i<n; i++){
char c=sc.next().charAt(0);
int x=sc.nextInt();
int y=sc.nextInt();
if(c=='x'){
segs[i]=new Seg(0, x, y, x+1, y);
}else{
segs[i]=new Seg(1, x, y, x, y+1);
}
}
solve();
}
}
void solve(){
P p0=new P(0.75, 0.25);
P p=new P(0.75, 0.25);
P v=new P(1, 1);
Seg[] walls=new Seg[4];
walls[0]=new Seg(0, 0, 0, m, 0);
walls[1]=new Seg(0, 0, m, m, m);
walls[2]=new Seg(0, 0, 0, 0, m);
walls[3]=new Seg(0, m, 0, m, m);
for(int i=0; i<10; i++){
v=v.div(v.abs()).mul(2*m);
if(p.sub(p0).abs()>EPS&&disSP(p, p.add(v), p0)<EPS){
int x=(int)(p0.x*100+EPS);
int y=(int)(p0.y*100+EPS);
println(x+" "+y);
break;
}
Seg seg=null;
P p2=null;
double min=INF;
for(Seg s : segs){
if(crsSS(p, p.add(v), s.p1, s.p2)){
P q=isLL(p, p.add(v), s.p1, s.p2);
double d=p.sub(q).abs();
if(d<min+EPS&&d>EPS){
seg=s;
p2=q;
min=p.sub(q).abs();
}
}
}
if(p2!=null){
p=p2;
if(seg.d==0){
v.y=-v.y;
}else{
v.x=-v.x;
}
}else{
for(Seg s : walls){
if(crsSS(p, p.add(v), s.p1, s.p2)){
P q=isLL(p, p.add(v), s.p1, s.p2);
if(p.sub(q).abs()>EPS){
int x=(int)(q.x*100+EPS);
int y=(int)(q.y*100+EPS);
println(x+" "+y);
}
}
}
break;
}
}
}
// 線分と点の距離
double disSP(P p1, P p2, P q){
if(p2.sub(p1).dot(q.sub(p1))<EPS)
return q.sub(p1).abs();
if(p1.sub(p2).dot(q.sub(p2))<EPS)
return q.sub(p2).abs();
return disLP(p1, p2, q);
}
// 直線と点の距離
double disLP(P p1, P p2, P q){
return abs(p2.sub(p1).det(q.sub(p1)))/p2.sub(p1).abs();
}
// 線分と線分の交差判定
boolean crsSS(P p1, P p2, P q1, P q2){
if(max(p1.x, p2.x)+EPS<min(q1.x, q2.x))
return false;
if(max(q1.x, q2.x)+EPS<min(p1.x, p2.x))
return false;
if(max(p1.y, p2.y)+EPS<min(q1.y, q2.y))
return false;
if(max(q1.y, q2.y)+EPS<min(p1.y, p2.y))
return false;
return signum(p2.sub(p1).det(q1.sub(p1)))
*signum(p2.sub(p1).det(q2.sub(p1)))<EPS
&&signum(q2.sub(q1).det(p1.sub(q1)))
*signum(q2.sub(q1).det(p2.sub(q1)))<EPS;
}
// 直線と直線の交点
P isLL(P p1, P p2, P q1, P q2){
double d=q2.sub(q1).det(p2.sub(p1));
if(abs(d)<EPS)
return null;
return p1.add(p2.sub(p1).mul(q2.sub(q1).det(q1.sub(p1))/d));
}
class Seg{
int d;
P p1, p2;
Seg(int d, int x1, int y1, int x2, int y2){
this.d=d;
p1=new P(x1, y1);
p2=new P(x2, y2);
}
}
// 2 dimensions
class P{
double x, y;
P(){
this(0, 0);
}
P(double x, double y){
this.x=x;
this.y=y;
}
P add(P p){
return new P(x+p.x, y+p.y);
}
P sub(P p){
return new P(x-p.x, y-p.y);
}
P mul(double m){
return new P(x*m, y*m);
}
P div(double d){
return new P(x/d, y/d);
}
double abs(){
return Math.sqrt(abs2());
}
double abs2(){
return x*x+y*y;
}
double arg(){
return Math.atan2(y, x);
}
// inner product
double dot(P p){
return x*p.x+y*p.y;
}
// outer product
double det(P p){
return x*p.y-y*p.x;
}
P rot90(){
return new P(-y, x);
}
// conjugation
P conj(){
return new P(x, -y);
}
}
void debug(Object... os){
System.err.println(Arrays.deepToString(os));
}
void print(String s){
System.out.print(s);
}
void println(String s){
System.out.println(s);
}
public static void main(String[] args){
// System.setOut(new PrintStream(new BufferedOutputStream(System.out)));
new Main().run();
}
}
0 件のコメント:
コメントを投稿