ハル研究所プログラミングコンテスト2012 工夫した点とか
方針とか
- 10^6回してみたけど、針を踏まない、開始地点以外で待機しなくてもゴールにたどり着けたので、「針を踏まない方向への移動」 + 「アイテム使用」のみを考えるA*で解いた
- ゴールまでの距離をBFSで計算して、ヒュースティック値にする
- memo化する際に、[ゲームのターン数][縦][横][アイテムの残り時間] の配列で保存していたが、
- ゲームのマス目は210でループするので、ターン数が210を超えた時は、 -210してあげても問題ない
- [アイテムの残り時間][縦][横][ゲームのターン数]の方が、キャッシュに乗りやすくて早かった
- ヒュースティック値と、現在の超過コストをkeyとして、priority_queueに入れて回す。
工夫(高速化)したところ
- classで実装しているもののほとんどをinline関数に書き換える
- int,shortを控えてcharにする(2倍は変わる)
- 関数の引数が4つくらいある場合は、引数をstructかclassにして、const &で渡した方が呼び出しが早くなる
- charの変数を初期化する際、intにキャストして代入することで、初期化が4倍くらい早くなる
char _penalty[5 + 1][24][24][210]; void init(){ for(int i = 0; i < 725760 / 4; i += 16){ ((int*)_penalty)[i+15] = ((int*)_penalty)[i+14] = ... ((int*)_penalty)[i+0] = 0x70707070; } }
- 現在いる場所のヒュースティック値と現在の超過コストを比較する際、shortに無理矢理キャストすることで比較演算の速度を上げる
priority_queue使ってたので比較演算の速度を上げると1.5倍くらい早くなった気がする
ただし、ビッグエンディアンなのでソースがローカルとサーバー側で変える必要がある。
こんな感じ
#define FORCE_SHORT(x) (((short *)(void *)&(x))[0]) //サーバと自分のPCではエンディアンが違うので、FORCE_SHORTでの比較が可能になるように変更しておく struct Result{ #ifdef DEBUG char heu; char penalty; #else char penalty; char heu; #endif short item_time; short turn; Result(){} Result(short turn,short item_time,char penalty,char heu) : turn(turn),item_time(item_time),penalty(penalty),heu(heu) {} short Point() const{ return _turnbouns - penalty + _nonStopBouns + 10; } }; ... inline bool Greater(const Result& l,const Result& r) { return FORCE_SHORT(l) < FORCE_SHORT(r); } inline bool LessThan(const Result& l,const Result& r) { return FORCE_SHORT(l) >= FORCE_SHORT(r); }
- forループを展開して書く
よく
int dx[] = {1,0,-1,0}; int dy[] = {0,1,0,-1}; for(int i = 0 ; i < 4; i++){ int nx = x + dx[i],ny = y + dy[i]; call_any_functions(); }
みたいなことをするんですが、
Pos next_pos = cur_pos; //左 next_pos.x -= 1 call_any_function(); //右 next_pos.x += 2 call_any_function(); //下 next_pos.x -= 1 next_pos.y -= 1 call_any_function(); //上 next_pos.y -= 1 call_any_function();
って要領で書くと早くなった
とりあえず思いつく限り書いてみました