2011/08/15

Codechef 2011 August Long-contest 参戦記(一問だけ)


長期の大会に初めて参加しました!(高校の時に参加したSuperconを別にすれば、ですが) 初体験で、どうかなと思っていたのですが、これからはTopcoderのmarathonも含めて、参加してみていいなと思いました。とはいえ、忙しい時期もよくあるので、参加できる範囲で、ということにします。

今回私は "Infinite Grid Game"という問題を解きました。そこで、このアルゴリズムを説明しようと思います。

簡単のため、ゴールを(0,0)とします。平行移動すれば同値であることがわかるはずです。
さて、もしもコマが(n,0),(0,n),(n,n) (nは自然数です)のどれかにあれば、次に動かすプレイヤーが勝つことがわかります。
ですので、これらの負ける点には動かすべきではありません。しかし、(1,2)や(2,1)にあった場合、 これらの負ける点に動かさねばなりません。つまり、(1,2)または(2,1)に動かしたほうが勝ちです。ということは、(1,3),(1,4),...と、負ける点が判明します。
これを繰り返していくと、勝ち負けの地図ができますので、これを作ればOKです。

例えばボブが勝つのは:(1,2),(2,1),(3,5),(5,3) ...であり、他の点ならアリスに軍配が上がります。

地図を作って出力する、というプロセスで、簡単に問題をとくことができますね。

コンテスト内での順位は116位でした。
ロングコンテストでのRatingがnon-ratedから2.787になり1785位となりました。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define NUM 1000

int main(void){
  int m,n,i,j,k,x,y;
  int t,p,q;
  short board[NUM][NUM];

  memset(board,0,sizeof(board));
  for(i=0;i<=2000;i++){
    for(j=0;j<=i;j++){
      if(j>=1000) break;
      if(abs(i-j)>=1000) continue;
      if(board[j][abs(i-j)]!=0) continue;
      for(x=j+1;x<1000;x++) board[x][abs(i-j)]=1;
      for(y=abs(i-j)+1;y<1000;y++) board[j][y]=1;
      for(k=1;j+k<1000 && abs(i-j)+k<1000;k++) board[j+k][abs(i-j)+k]=1;
    }
  }
  scanf("%d",&t);
  while(t--){
    scanf("%d %d %d %d",&m,&n,&p,&q);
    if(board[m-p][n-q]==0) puts("Bob");
    else puts("Alice");
  }
  return 0;
}

0 件のコメント:

コメントを投稿