模擬地区予選2010 F.Two-Wheel Buggy

F. Two-Wheel Buggy

AOJに投げてみたらコードサイズがだいぶ小さかったので晒してみます。
嘘の告発は大歓迎です。

解法

  • 直進か曲がるかの2通りに場合分けして処理する
  • 車の状態は,2個のタイヤの中点pと車の方向dirによって管理
  • 直進(左右の回転数が一緒)はやるだけ
    • 向いてる方向にまっすぐ進める
  • 曲がる(左右の回転数が違うとき)ときは以下の通り
    • pの回転中心cは2つのタイヤの中心を結ぶ直線上にある
    • 左右のタイヤが描く円周の長さの比から式を立てると、
      • c = p + P(cos(dir-pi/2), sin(dir-pi/2))*(L+R)/(L-R)*D となる
      • これはL,Rの正負によらず同じ式。
      • ちなみにL==R(直進)だと回転半径が無限大という扱い
    • 後は回転数から回転角を求めて車を移動させる
#include <iostream>
#include <fstream>
#include <complex>
#include <cmath>
#include <stdio.h>

using namespace std;

typedef complex<double> P;

const double PI = acos(-1.0);

int main(){
    int N, D;
    ifstream fin("F.txt");
    while(fin >> N >> D, N){
        P p = P(0,0); double dir = PI/2;
        for(int i=0;i<N;i++){
            int L, R, T; fin >> L >> R >> T;
            if(L==R){
                p = p + T*L/180.0*PI*P(cos(dir), sin(dir));
            }
            else {
                double r = ((double)L+R)/(L-R)*D;
                P c = p + P(cos(dir), sin(dir))*P(0,-1)*r;
                double agl = (r > 0 ? -L/abs(r+D) : R/abs(r-D))*T*PI/180.0;
                dir += agl;
                p = (p-c)*P(cos(agl), sin(agl))+c;
            }
        }
        printf("%.8lf\n%.8lf\n", real(p), imag(p));
    }
}