AOJ : 1212 - Mirror Illusion
問題概要
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1212
問題文の図のような部屋があり, (0.75,0.25)の位置で, (1.0,0.5)の方向を向いて人が立っている.
また, この部屋には, 鏡がいくつか置いてある.
このとき, 立っている人は, 周りの壁のどこの座標を見るか答えよ.
(もし, 自分が見える場合は, 自分の座標を答えよ)
アルゴリズム
解法1
- 幾何で解く
- 現在の位置, 向いている方向から, 次はどの鏡で反射するか求める
- 鏡に反射する前に, 自分が見えるならば, 自分の座標を出力.
- 鏡に反射しないならば, 壁の座標を答えればいい.
解法2
- 人の視線は, 鏡の面に向かって必ず入射角45度.
- 幾何なんてしなくても, この性質を利用してシミュレーションで解ける.
プログラム
バカみたいに, 解法1で解いてしまいました.
typedef complex<double> P; const double INF = 99999; bool intersectSS(P a,P b,P c,P d){...} bool intersectSP(P a,P b,P p){...} P crosspoint(P a,P b,P c,P d){...} int n; char dch[150]; P from[150],to[150]; //自分の座標と, 向く方向を更新 //now:自分の位置, dp:視線の先の座標 void getNext(P &now,P &dp,P p,int mirror){ dp = now; if(dch[mirror] == 'y'){ double dist = abs(now.imag() - p.imag()); if(now.imag() > p.imag()){ dp.imag() -= dist * 2; } else{ dp.imag() += dist * 2; } } else{ double dist = abs(now.real() - p.real()); if(now.real() > p.real()){ dp.real() -= dist * 2; } else{ dp.real() += dist * 2; } } now = p; dp = now + INF * (dp - now); //無限に伸ばした線分にする } int main(){ while(cin>>n,n>=0){ rep(i,n){ double x,y; cin>>dch[i]>>x>>y; from[i] = P(x,y); to[i] = (dch[i] == 'x' ? P(x+1,y) : P(x,y+1)); } //壁4つ from[n] = to[n+3] = P(0,0); from[n+1] = to[n] = P(8,0); from[n+2] = to[n+1] = P(8,8); from[n+3] = to[n+2] = P(0,8); //now:自分がいる場所, dp:視線の先の座標 //視線は, nowから伸びる無限の線分として表す P now(0.75,0.25); P dp = now + INF * (P(1,0.5) - now); bool himself = false; while(1){ int minIdx = -1; P minP; double minDist = INF; //視線と衝突する, 現在いる場所から一番近い鏡を探す rep(i,n){ if(intersectSS(from[i],to[i],now,dp)){ P p = crosspoint(from[i],to[i],now,dp); double dist = abs(p - now); if(dist > EPS && dist < minDist){ minIdx = i; minDist = dist; minP = p; } } } //視線と初期位置が衝突した場合 if(intersectSP(now,dp,P(0.75,0.25))){ double dist = abs(P(0.75,0.25) - now); if(dist > EPS && dist < minDist){ himself = true; break; } } //壁が見えたとき if(minIdx == -1) break; getNext(now,dp,minP,minIdx); } if(himself){ printf("75 25\n"); continue; } //壁の座標を求める rep(i,4){ if(intersectSS(from[n+i],to[n+i],now,dp)){ P p = crosspoint(from[n+i],to[n+i],now,dp); if(abs(p - now) < EPS) continue; printf("%d %d\n",(int)(p.real()*100),(int)(p.imag()*100)); } } } }