2011年12月27日火曜日

TopCoder SRM295 Div2 300Pts

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

とてもわくわくするジャンケントーナメントが始まりました!予選では、各プレーヤはすべての相手と向かい合って5回手を出します。各勝負では、プレーヤはグー(P)、チョキ(S)、パー(S)の中から1つ選びます。1回の勝負は次のように決まります。パーはグーに勝ち、グーはチョキに勝ち、チョキはパーに勝つ。もし二人が同じ手を出したなら、どちらの勝ちにもなりません。ゲームの勝者は5回の勝負でより勝った方になります。もし、二人が同じ勝ち数であったら、ゲームは同点と扱われます(予選なので、同点も許されます)。予選を抜ける人を決めるため、得点システムを次のようにします。このゲームに勝つと、1点、同点なら0.5点、負けなら0点とします。もっとも点数を得た1人だけが予選を抜けます。もし複数のプレーヤが同じ点数で並んだ場合は、入力で一番最初に現れた人が勝つものとします。

すべてのプレーヤは単純な戦略に従います。それは全員が出す手の順番を用意しておき、すべてのゲームで同じ手をその順で出すというものです。players[]というか各プレーヤーの出す手を表す配列が与えられたときに、予選を抜けたプレーヤの添え字を返せ(先頭のプレーヤの添え字は0から始まるものとする)。プレーヤの各要素は5文字であり、Pはグー、Sはチョキ、Rはグーを表すものとする。

私の解答はこちら。

public class PaperRockScisQuals {

 public int whoPassed(String[] players) {
  // 問題文では勝負の結果で1、0.5、0点与えるとあるが、2倍しても答は変わらないので、
  // 2、1、0という点数を与えるようにしておく。こうすると整数値で扱える。
  int[] points = new int[players.length];
  for( int i=0 ; i<players.length ; i++ ){
   for( int j=i+1 ; j<players.length ; j++ ){
    String iHands = players[i];
    String jHands = players[j];
    int iWin = 0;
    int jWin = 0;
    for( int k=0 ; k<players[i].length() ; k++ ){
     int res = judge(iHands.charAt(k), jHands.charAt(k));
     if( res > 0 ){
      iWin++;
     }else if( res < 0 ){
      jWin++;
     }
    }
    if( iWin > jWin ){ // iとjに点数を与える
     points[i] += 2;
    }else if( iWin == jWin ){
     points[i]++;
     points[j]++;
    }else{
     points[j] += 2;
    }
   }
  }
  int idx = -1;
  int max = -1;
  for( int i=0 ; i<points.length ; i++ ){ // 最高点判定ロジック
   if( points[i] > max ){
    max = points[i];
    idx = i;
   }
  }
  return idx;
 }
 private int judge(char i,char j){ // ジャンケンの勝負判定ロジック
  if( i == j ){ // 同じ手
   return 0;
  }else if( (i == 'P' && j == 'R') || (i == 'S' && j == 'P') || (i == 'R' && j == 'S') ){
   return 1; // iの勝ち
  }else{
   return -1; // jの勝ち
  }
 }
}

得点は165.76/300、中央値は約185点。当初は最初から見て最初に勝った方が勝者という判定ロジックを書いていたため、5回のジャンケンの結果で判定を行わないといけないということに気付かず、解答が遅くなってしまった。また、日本語と英語でジャンケンの手の名称が異なるため、しっくりこない感もあるが、PはPaper(紙)、SはScissors(ハサミ)、RはRock(岩)という英単語の略である。

0 件のコメント:

コメントを投稿

フォロワー

ブログ アーカイブ

ページビューの合計