2012年7月11日水曜日

TopCoder SRM407 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文について意訳で説明する。

長方形のセルを左上から右上、右下、左下の方向へ順に、ぐるぐると渦を巻くように回る。全部のマスを回ったところで動きは止まる。既に通ったマス、あるいはセルの範囲を飛び出す場合は先に進めないので向きを時計回りに90度変える。進む向きを変えた位置にあるセルを除いて、通過したセルに書かれている数値の合計を計算して返すメソッドを作成せよ。最初と止まった位置も合計に加えることを忘れないこと。なお、セルは文字列型配列で管理されており、i番目の要素のj番目の文字がセル(i, j)とその位置に書かれている値を表している。

私の解答はこちら。

public class SpiralWalking {

 public int totalPoints(String[] levelMap) {
  int nrow = levelMap.length;
  int ncol = levelMap[0].length();
  boolean[][] isVisited = new boolean[nrow][ncol]; // 通過したセルを管理するフラグ
  int dir = 0; // 向いている方向(0~3)
  int[] xdir = {0, 1, 0, -1}; // 順に右、下、左、上方向に動く量を表している
  int[] ydir = {1, 0, -1, 0}; // 上に同じ。なお、xdirは行方向、ydirは列方向の移動量である。
  int total = 0; // 返す値の合計を管理
  int xpos = 0; // 現在の位置(行方向)
  int ypos = 0; // 現在の位置(列方向)
  boolean turned = false; // 向きを変えたか否かを管理するフラグ
  while( true ){
   int val = levelMap[xpos].charAt(ypos) - '0'; // 値を計算して
   total += val; // 追加
   isVisited[xpos][ypos] = true; // 訪問済に変更
   int currentdir = dir; // 現在の向きを記憶
   turned = false; // 向きを変えていない
   // もし、その向きで進んだらセルを飛び出す、あるいは訪問済みのセルに進むのであれば、
   // 向きを90度変える
   while( xpos+xdir[dir] >= nrow || xpos+xdir[dir] < 0 ||
    ypos+ydir[dir] >= ncol || ypos+ydir[dir] < 0 ||
    isVisited[xpos+xdir[dir]][ypos+ydir[dir]] ){
    dir = (dir+1) % xdir.length;
    turned = true;
    if( dir == currentdir ) return total; // 結局向きが1周したら、訪問するセルは残っていない
   }
   if( turned ) total -= val; // 向きを変えていたなら、値の加算はなかったことにする
   xpos += xdir[dir]; // 次のセルの位置へ進む
   ypos += ydir[dir];
  }
 }

}

得点は117.42/250、1回のsubmitでシステムテストクリア。中央値は75点。規則性があるので、上手く書けば実はループが不要にできるのではないかと思うのですが...

0 件のコメント:

コメントを投稿

フォロワー

ページビューの合計