読者です 読者をやめる 読者になる 読者になる

土下座しながら探索中

主に競技プログラミング

AOJ 1171 : Laser Beam Reflections

問題リンク : Laser Beam Reflections | Aizu Online Judge

解法:
レーザービームを打つ方向を360度ちょっとずつずらしながらシュミレーションした
レーザービームを打つ方向さえ決めてしまえばそこからゴールまで到達できるかどうかは一意に定まるので判定しながら距離を計算して最小のものを出力した
EPSを1e-5に設定してループで角度を0.001だけずらしながら計算したらACした

他の人と1.5秒近く差があるのが気掛かり

コード:

int n;
vector<Segment> seg;
Point s,t;

double compute(double rad)
{
  Point e = Point(cos(rad),sin(rad));
  e = e * 1000;
  e = e + s;
  Segment UruruBeam = Segment(s,e);


  double ret = 0;
  Point sp;
  int onSeg = -1;
  sp = s;
  rep(i,6)
    {
      double mdist = inf;
      Point mcp;
      int mp = -1;
      rep(j,n)if(onSeg != j && intersectSS(UruruBeam,seg[j]))
	{
	  Point cp = crosspoint(UruruBeam,seg[j]);
	  double dist = abs(sp-cp);
	  if(!equals(mdist,dist) && mdist > dist)
	    {
	      mdist = dist;
	      mcp = cp;
	      mp = j;
	    }
	}

      if(intersectSP(UruruBeam,t))
	{
	  double dist = abs(sp-t);
	  if(!equals(mdist,dist) && mdist > dist)return ret + dist;
	}

      if(mp == -1)return inf;
	
      onSeg = mp;
      ret += abs(sp-mcp);
      UruruBeam = Segment(mcp,reflection(seg[mp],UruruBeam.p2));
      sp = mcp;

    }
  return inf;
}

int main()
{
  while(scanf("%d",&n),n)
    {
      seg.clear();
      seg.resize(n);
      rep(i,n)scanf("%lf %lf %lf %lf",&seg[i].p1.x,&seg[i].p1.y,&seg[i].p2.x,&seg[i].p2.y);
      scanf("%lf %lf",&t.x,&t.y);
      scanf("%lf %lf",&s.x,&s.y);

      double ans = inf;
      for(double theta=0.0,cnt=0;cnt <= 360000;theta+=0.001,cnt++)
	{
	  ans = min(ans,compute(toRad(theta)));
	}
      printf("%.10lf\n",ans);
    }
  return 0;
}