■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 件のコメント:
コメントを投稿